{"model_name":"gpt-5.4-medium","codes":{"1":{"ahc001":"#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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct State {\n    double score;\n    vector<Rect> rects;\n};\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr double TL = 4.95;\n\nint n;\nvector<int> X, Y;\nvector<long long> Rr;\n\nTimer timer;\nmt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline long long area(const Rect& r) {\n    return 1LL * (r.c - r.a) * (r.d - r.b);\n}\n\ninline double sat(long long s, long long r) {\n    double q = (double)min(s, r) / (double)max(s, r);\n    double t = 1.0 - q;\n    return 1.0 - t * t;\n}\n\ndouble total_score(const vector<Rect>& rects) {\n    double res = 0.0;\n    for (int i = 0; i < n; ++i) {\n        res += sat(area(rects[i]), Rr[i]);\n    }\n    return res;\n}\n\ninline bool hoverlap(const Rect& x, const Rect& y) {\n    return max(x.a, y.a) < min(x.c, y.c);\n}\n\ninline bool voverlap(const Rect& x, const Rect& y) {\n    return max(x.b, y.b) < min(x.d, y.d);\n}\n\n// ---------------- Partition construction ----------------\n\nstruct Cand {\n    long double cost;\n    bool vertical; // true: vertical split, false: horizontal split\n    int k;\n    int cut;\n};\n\nvoid split_rec(const vector<int>& ids, int L, int R, int B, int T,\n               vector<Rect>& leaf_box, bool randomized, long double shape_lambda) {\n    int m = (int)ids.size();\n    if (m == 1) {\n        leaf_box[ids[0]] = {L, B, R, T};\n        return;\n    }\n\n    long long sumR = 0;\n    for (int id : ids) sumR += Rr[id];\n\n    vector<int> sx = ids, sy = ids;\n    sort(sx.begin(), sx.end(), [&](int i, int j) { return X[i] < X[j]; });\n    sort(sy.begin(), sy.end(), [&](int i, int j) { return Y[i] < Y[j]; });\n\n    vector<Cand> cands;\n    cands.reserve(2 * (m - 1));\n\n    int W = R - L;\n    int H = T - B;\n\n    // Vertical splits\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sx[k - 1]];\n            int minC = X[sx[k - 1]] + 1;\n            int maxC = X[sx[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)L + (long double)W * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int w1 = cut - L;\n            int w2 = R - cut;\n            if (w1 <= 0 || w2 <= 0) continue;\n\n            long double desiredW = (long double)W * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)w1 - desiredW) / (long double)W;\n\n            long double shape = fabsl(log((long double)w1 / (long double)H))\n                              + fabsl(log((long double)w2 / (long double)H));\n\n            cands.push_back({err + shape_lambda * shape, true, k, cut});\n        }\n    }\n\n    // Horizontal splits\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sy[k - 1]];\n            int minC = Y[sy[k - 1]] + 1;\n            int maxC = Y[sy[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)B + (long double)H * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int h1 = cut - B;\n            int h2 = T - cut;\n            if (h1 <= 0 || h2 <= 0) continue;\n\n            long double desiredH = (long double)H * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)h1 - desiredH) / (long double)H;\n\n            long double shape = fabsl(log((long double)W / (long double)h1))\n                              + fabsl(log((long double)W / (long double)h2));\n\n            cands.push_back({err + shape_lambda * shape, false, k, cut});\n        }\n    }\n\n    if (cands.empty()) {\n        // Should not happen, but just in case split by x median.\n        vector<int> tmp = sx;\n        int k = m / 2;\n        int cut = max(X[tmp[k - 1]] + 1, min(X[tmp[k]], (L + R) / 2));\n        vector<int> left(tmp.begin(), tmp.begin() + k);\n        vector<int> right(tmp.begin() + k, tmp.end());\n        split_rec(left, L, cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, cut, R, B, T, leaf_box, randomized, shape_lambda);\n        return;\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Cand& p, const Cand& q) {\n        return p.cost < q.cost;\n    });\n\n    int pick = 0;\n    if (randomized) {\n        int top = min<int>(6, cands.size());\n        vector<long long> w(top);\n        long long s = 0;\n        for (int i = 0; i < top; ++i) {\n            w[i] = top - i; // simple bias toward better candidates\n            s += w[i];\n        }\n        long long z = (long long)(rng() % s);\n        int chosen = 0;\n        while (z >= w[chosen]) {\n            z -= w[chosen];\n            ++chosen;\n        }\n        pick = chosen;\n    }\n\n    Cand best = cands[pick];\n\n    if (best.vertical) {\n        vector<int> left(sx.begin(), sx.begin() + best.k);\n        vector<int> right(sx.begin() + best.k, sx.end());\n        split_rec(left, L, best.cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, best.cut, R, B, T, leaf_box, randomized, shape_lambda);\n    } else {\n        vector<int> down(sy.begin(), sy.begin() + best.k);\n        vector<int> up(sy.begin() + best.k, sy.end());\n        split_rec(down, L, R, B, best.cut, leaf_box, randomized, shape_lambda);\n        split_rec(up, L, R, best.cut, T, leaf_box, randomized, shape_lambda);\n    }\n}\n\nRect place_inside_box(const Rect& box, int id) {\n    int W = box.c - box.a;\n    int H = box.d - box.b;\n    long long boxA = 1LL * W * H;\n    long long target = Rr[id];\n\n    if (boxA <= target) {\n        return box;\n    }\n\n    long long bestA = -1;\n    int bestW = 1, bestH = 1;\n    long long bestShape = (1LL << 60);\n\n    for (int w = 1; w <= W; ++w) {\n        long long h = min<long long>(H, target / w);\n        if (h <= 0) continue;\n        long long a = 1LL * w * h;\n        long long shp = llabs((long long)w - h);\n        if (a > bestA || (a == bestA && shp < bestShape)) {\n            bestA = a;\n            bestW = w;\n            bestH = (int)h;\n            bestShape = shp;\n        }\n    }\n\n    int loA = max(box.a, X[id] + 1 - bestW);\n    int hiA = min(X[id], box.c - bestW);\n    int a = std::clamp(X[id] - bestW / 2, loA, hiA);\n    int c = a + bestW;\n\n    int loB = max(box.b, Y[id] + 1 - bestH);\n    int hiB = min(Y[id], box.d - bestH);\n    int b = std::clamp(Y[id] - bestH / 2, loB, hiB);\n    int d = b + bestH;\n\n    return {a, b, c, d};\n}\n\nvector<Rect> build_solution(bool randomized) {\n    vector<int> ids(n);\n    iota(ids.begin(), ids.end(), 0);\n\n    long double shape_lambda;\n    if (!randomized) {\n        shape_lambda = 0.0015L;\n    } else {\n        int t = (int)(rng() % 4);\n        if (t == 0) shape_lambda = 0.0L;\n        else if (t == 1) shape_lambda = 0.0008L;\n        else if (t == 2) shape_lambda = 0.0015L;\n        else shape_lambda = 0.0030L;\n    }\n\n    vector<Rect> boxes(n);\n    split_rec(ids, 0, BOARD, 0, BOARD, boxes, randomized, shape_lambda);\n\n    vector<Rect> rects(n);\n    for (int i = 0; i < n; ++i) {\n        rects[i] = place_inside_box(boxes[i], i);\n    }\n    return rects;\n}\n\n// ---------------- Local improvement ----------------\n\nstruct Op {\n    double gain = 0.0;\n    Rect nr;\n};\n\nvector<int> candidate_steps(long long diff, int dim, int tmax) {\n    vector<int> cand;\n    cand.reserve(16);\n    cand.push_back(1);\n    cand.push_back(tmax);\n    long double q = (long double)diff / (long double)dim;\n    long long f = (long long)floor((double)q);\n    long long c = (long long)ceil((double)q);\n    for (int d = -2; d <= 2; ++d) {\n        cand.push_back((int)(f + d));\n        cand.push_back((int)(c + d));\n    }\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    vector<int> res;\n    for (int t : cand) {\n        if (1 <= t && t <= tmax) res.push_back(t);\n    }\n    return res;\n}\n\nOp best_operation_for(int i, const vector<Rect>& rects) {\n    const Rect& curR = rects[i];\n    long long s = area(curR);\n    long long target = Rr[i];\n    double curSat = sat(s, target);\n\n    Op best;\n    best.nr = curR;\n\n    int w = curR.c - curR.a;\n    int h = curR.d - curR.b;\n\n    // Expand if under target\n    if (s < target) {\n        // left\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].c <= curR.a) {\n                    bound = max(bound, rects[j].c);\n                }\n            }\n            int tmax = curR.a - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].a >= curR.c) {\n                    bound = min(bound, rects[j].a);\n                }\n            }\n            int tmax = bound - curR.c;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].d <= curR.b) {\n                    bound = max(bound, rects[j].d);\n                }\n            }\n            int tmax = curR.b - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].b >= curR.d) {\n                    bound = min(bound, rects[j].b);\n                }\n            }\n            int tmax = bound - curR.d;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    // Shrink if over target\n    if (s > target) {\n        // left shrink\n        {\n            int tmax = X[i] - curR.a;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right shrink\n        {\n            int tmax = curR.c - (X[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down shrink\n        {\n            int tmax = Y[i] - curR.b;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up shrink\n        {\n            int tmax = curR.d - (Y[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            double sc = sat(area(rects[i]), Rr[i]);\n            double noise = (double)(rng() & 1023) * 1e-12;\n            ord.push_back({sc + noise, i});\n        }\n        sort(ord.begin(), ord.end()); // low-score rectangles first\n\n        bool changed = false;\n        for (auto [_, i] : ord) {\n            if (timer.elapsed() >= end_time) break;\n            while (timer.elapsed() < end_time) {\n                Op op = best_operation_for(i, rects);\n                if (op.gain <= 1e-15) break;\n                rects[i] = op.nr;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\nvoid add_state(vector<State>& states, vector<Rect> rects) {\n    double sc = total_score(rects);\n    states.push_back({sc, std::move(rects)});\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)states.size() > 3) states.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    X.resize(n);\n    Y.resize(n);\n    Rr.resize(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> X[i] >> Y[i] >> Rr[i];\n    }\n\n    vector<State> states;\n    add_state(states, build_solution(false));\n\n    // Generate several initial candidates\n    double gen_end = 0.8;\n    while (timer.elapsed() < gen_end) {\n        add_state(states, build_solution(true));\n    }\n\n    // Improve each top candidate a bit\n    double mid_end = 4.2;\n    for (int i = 0; i < (int)states.size(); ++i) {\n        double now = timer.elapsed();\n        if (now >= mid_end) break;\n        double slice = (mid_end - now) / (double)(states.size() - i);\n        improve(states[i].rects, now + slice);\n        states[i].score = total_score(states[i].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<Rect> best = states[0].rects;\n    improve(best, TL);\n\n    for (int i = 0; i < n; ++i) {\n        cout << best[i].a << ' ' << best[i].b << ' ' << best[i].c << ' ' << best[i].d << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int C = N * N;\n\n    int si, sj, start;\n    array<int, C> tile{};\n    array<int, C> val{};\n    array<array<int, 4>, C> adj{};\n    array<uint8_t, C> deg{};\n\n    int M = 0;\n    vector<int> tileWeight;\n\n    vector<unsigned char> vis;\n\n    vector<int> cellSeen;\n    vector<int> cellComp;\n    vector<int> tileSeen;\n    int evalStamp = 1;\n    int tileStamp = 1;\n\n    array<int, C> qbuf{};\n\n    XorShift rng;\n\n    vector<int> bestSeq;\n    vector<int> bestPrefixScore;\n    int bestScore = 0;\n\n    // exact endgame search\n    vector<int> exactBestPath;\n    vector<int> exactCurPath;\n    int exactBestScore = 0;\n\n    chrono::steady_clock::time_point t0;\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int r, int c) const { return r * N + c; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> si >> sj;\n        start = id(si, sj);\n\n        int mxTile = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int t;\n                cin >> t;\n                tile[id(r, c)] = t;\n                mxTile = max(mxTile, t);\n            }\n        }\n        M = mxTile + 1;\n\n        tileWeight.assign(M, 0);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p;\n                cin >> p;\n                int v = id(r, c);\n                val[v] = p;\n                tileWeight[tile[v]] = max(tileWeight[tile[v]], p);\n            }\n        }\n\n        // Build adjacency only between adjacent cells of DIFFERENT tiles.\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                int d = 0;\n                const int dr[4] = {-1, 1, 0, 0};\n                const int dc[4] = {0, 0, -1, 1};\n                for (int k = 0; k < 4; k++) {\n                    int nr = r + dr[k], nc = c + dc[k];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    int u = id(nr, nc);\n                    if (tile[u] == tile[v]) continue;\n                    adj[v][d++] = u;\n                }\n                deg[v] = (uint8_t)d;\n            }\n        }\n\n        vis.assign(M, 0);\n        cellSeen.assign(C, 0);\n        cellComp.assign(C, -1);\n        tileSeen.assign(M, 0);\n    }\n\n    struct ReachInfo {\n        int bestScore = 0;   // sum of tileWeight upper bound in best adjacent component\n        int bestTiles = 0;   // number of tiles in that best component\n        int branches = 0;    // number of distinct adjacent components\n        int availDeg = 0;    // number of available neighboring edges\n    };\n\n    // Analyze future reachable components when standing on `cell`.\n    // Available cells are those whose tiles are not visited and not equal to forbidTile.\n    // Among components adjacent to cell, keep the best component upper bound.\n    ReachInfo analyze_from_cell(int cell, const vector<unsigned char>& used, int forbidTile) {\n        ++evalStamp;\n\n        int compScore[4];\n        int compTiles[4];\n        int compCnt = 0;\n\n        int branchIds[4];\n        int branchCnt = 0;\n\n        ReachInfo res;\n\n        for (int i = 0; i < deg[cell]; i++) {\n            int s = adj[cell][i];\n            int ts = tile[s];\n            if (used[ts] || ts == forbidTile) continue;\n\n            res.availDeg++;\n\n            if (cellSeen[s] != evalStamp) {\n                int cid = compCnt++;\n                int qh = 0, qt = 0;\n                qbuf[qt++] = s;\n                cellSeen[s] = evalStamp;\n                cellComp[s] = cid;\n\n                ++tileStamp;\n                int score = 0;\n                int tiles = 0;\n\n                while (qh < qt) {\n                    int v = qbuf[qh++];\n                    int tv = tile[v];\n                    if (tileSeen[tv] != tileStamp) {\n                        tileSeen[tv] = tileStamp;\n                        score += tileWeight[tv];\n                        tiles++;\n                    }\n                    for (int j = 0; j < deg[v]; j++) {\n                        int u = adj[v][j];\n                        int tu = tile[u];\n                        if (used[tu] || tu == forbidTile) continue;\n                        if (cellSeen[u] == evalStamp) continue;\n                        cellSeen[u] = evalStamp;\n                        cellComp[u] = cid;\n                        qbuf[qt++] = u;\n                    }\n                }\n\n                compScore[cid] = score;\n                compTiles[cid] = tiles;\n            }\n\n            int cid = cellComp[s];\n            if (compScore[cid] > res.bestScore ||\n                (compScore[cid] == res.bestScore && compTiles[cid] > res.bestTiles)) {\n                res.bestScore = compScore[cid];\n                res.bestTiles = compTiles[cid];\n            }\n\n            bool exists = false;\n            for (int b = 0; b < branchCnt; b++) {\n                if (branchIds[b] == cid) {\n                    exists = true;\n                    break;\n                }\n            }\n            if (!exists) branchIds[branchCnt++] = cid;\n        }\n\n        res.branches = branchCnt;\n        return res;\n    }\n\n    struct Cand {\n        int to;\n        int eval;\n        int imm;\n        int future;\n        int branches;\n        int availDeg;\n    };\n\n    static bool cand_cmp(const Cand& a, const Cand& b) {\n        if (a.eval != b.eval) return a.eval > b.eval;\n        if (a.future != b.future) return a.future > b.future;\n        if (a.imm != b.imm) return a.imm > b.imm;\n        if (a.branches != b.branches) return a.branches > b.branches;\n        return a.availDeg > b.availDeg;\n    }\n\n    void update_best(const vector<int>& seq, int score) {\n        if (score <= bestScore) return;\n        bestScore = score;\n        bestSeq = seq;\n        bestPrefixScore.resize(seq.size());\n        int s = 0;\n        for (int i = 0; i < (int)seq.size(); i++) {\n            s += val[seq[i]];\n            bestPrefixScore[i] = s;\n        }\n    }\n\n    void exact_dfs(int cur, vector<unsigned char>& used, int curScore) {\n        // Upper bound prune\n        ReachInfo ub = analyze_from_cell(cur, used, -1);\n        if (curScore + ub.bestScore <= exactBestScore) return;\n\n        Cand cs[4];\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            int tnx = tile[nx];\n            if (used[tnx]) continue;\n            ReachInfo ri = analyze_from_cell(nx, used, tnx);\n            int ev = val[nx] + ri.bestScore + 6 * ri.branches + 2 * ri.availDeg;\n            cs[cc++] = Cand{nx, ev, val[nx], ri.bestScore, ri.branches, ri.availDeg};\n        }\n\n        if (cc == 0) {\n            if (curScore > exactBestScore) {\n                exactBestScore = curScore;\n                exactBestPath = exactCurPath;\n            }\n            return;\n        }\n\n        sort(cs, cs + cc, cand_cmp);\n\n        for (int i = 0; i < cc; i++) {\n            int nx = cs[i].to;\n            int tnx = tile[nx];\n            used[tnx] = 1;\n            exactCurPath.push_back(nx);\n            exact_dfs(nx, used, curScore + val[nx]);\n            exactCurPath.pop_back();\n            used[tnx] = 0;\n        }\n    }\n\n    vector<int> exact_finish(int cur, vector<unsigned char>& used) {\n        exactBestPath.clear();\n        exactCurPath.clear();\n        exactBestScore = 0;\n        exact_dfs(cur, used, 0);\n        return exactBestPath;\n    }\n\n    pair<vector<int>, int> grow_from_prefix(int cutMoves, double baseQ) {\n        fill(vis.begin(), vis.end(), 0);\n\n        vector<int> seq;\n        seq.reserve(C);\n\n        int score = 0;\n        for (int i = 0; i <= cutMoves; i++) {\n            int v = bestSeq[i];\n            seq.push_back(v);\n            vis[tile[v]] = 1;\n        }\n        score = bestPrefixScore[cutMoves];\n\n        int cur = seq.back();\n\n        constexpr int ENDGAME_LIMIT = 16;\n\n        while (true) {\n            // exact endgame\n            ReachInfo curInfo = analyze_from_cell(cur, vis, -1);\n            if (curInfo.bestTiles <= ENDGAME_LIMIT) {\n                vector<int> suf = exact_finish(cur, vis);\n                for (int nx : suf) {\n                    vis[tile[nx]] = 1;\n                    seq.push_back(nx);\n                    score += val[nx];\n                    cur = nx;\n                }\n                break;\n            }\n\n            Cand cs[4];\n            int cc = 0;\n            for (int i = 0; i < deg[cur]; i++) {\n                int nx = adj[cur][i];\n                int tnx = tile[nx];\n                if (vis[tnx]) continue;\n\n                ReachInfo ri = analyze_from_cell(nx, vis, tnx);\n                int ev = val[nx] + ri.bestScore + 6 * ri.branches + 2 * ri.availDeg;\n                cs[cc++] = Cand{nx, ev, val[nx], ri.bestScore, ri.branches, ri.availDeg};\n            }\n\n            if (cc == 0) break;\n            sort(cs, cs + cc, cand_cmp);\n\n            int pick = 0;\n            if (cc >= 2) {\n                int gap = cs[0].eval - cs[1].eval;\n                double q = baseQ;\n                if (gap > 3000) q *= 0.05;\n                else if (gap > 1500) q *= 0.15;\n                else if (gap > 700) q *= 0.35;\n                else if (gap > 300) q *= 0.60;\n                else if (gap > 100) q *= 0.85;\n                else q *= 1.15;\n                if (q > 0.85) q = 0.85;\n\n                while (pick + 1 < cc && rng.next_double() < q) pick++;\n            }\n\n            int nx = cs[pick].to;\n            vis[tile[nx]] = 1;\n            seq.push_back(nx);\n            score += val[nx];\n            cur = nx;\n        }\n\n        return {seq, score};\n    }\n\n    string seq_to_answer(const vector<int>& seq) {\n        string ans;\n        ans.reserve(max(0, (int)seq.size() - 1));\n        for (int i = 1; i < (int)seq.size(); i++) {\n            int a = seq[i - 1], b = seq[i];\n            if (b == a - N) ans.push_back('U');\n            else if (b == a + N) ans.push_back('D');\n            else if (b == a - 1) ans.push_back('L');\n            else ans.push_back('R');\n        }\n        return ans;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        bestSeq = {start};\n        bestPrefixScore = {val[start]};\n        bestScore = val[start];\n\n        // Initial deterministic greedy.\n        {\n            auto [seq, score] = grow_from_prefix(0, 0.0);\n            update_best(seq, score);\n        }\n\n        int iter = 0;\n        const double TL = 1.95;\n\n        while (elapsed() < TL) {\n            int L = (int)bestSeq.size() - 1; // number of moves\n            int cut = 0;\n\n            if (L > 0) {\n                uint32_t mode = rng.next_u32() % 5;\n                if (mode == 0) {\n                    cut = 0; // full restart\n                } else if (mode == 1) {\n                    double u = rng.next_double();\n                    cut = (int)(L * u * u); // bias to earlier changes\n                } else if (mode == 2) {\n                    double u = rng.next_double();\n                    cut = (int)(L * u); // uniform\n                } else {\n                    double u = rng.next_double();\n                    cut = L - (int)(L * u * u); // bias to later suffix tuning\n                    if (cut < 0) cut = 0;\n                    if (cut > L) cut = L;\n                }\n            }\n\n            double baseQ = 0.06 + 0.28 * rng.next_double();\n            auto [seq, score] = grow_from_prefix(cut, baseQ);\n            update_best(seq, score);\n\n            iter++;\n        }\n\n        cout << seq_to_answer(bestSeq) << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horizontal; // true: h[i][j], false: v[i][j]\n    int i, j;\n};\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr double INF = 1e100;\n\n    // Raw online estimates\n    double raw_h[N][N - 1];\n    double raw_v[N - 1][N];\n    int cnt_h[N][N - 1];\n    int cnt_v[N - 1][N];\n\n    // Smoothed costs for routing / prediction\n    double base_h[N][N - 1];\n    double base_v[N - 1][N];\n\n    // Slightly perturbed costs for exploration during search\n    double search_h[N][N - 1];\n    double search_v[N - 1][N];\n\n    // Fixed random values in [-1,1] for exploration noise\n    double rnd_h[N][N - 1];\n    double rnd_v[N - 1][N];\n\n    mt19937 rng;\n\n    static double clamp_cost(double x) {\n        if (x < 1000.0) return 1000.0;\n        if (x > 9000.0) return 9000.0;\n        return x;\n    }\n\n    void build_model(int turn) {\n        constexpr double PRIOR_MEAN = 5000.0;\n        constexpr double PRIOR_SEG_WEIGHT = 1.0;\n        constexpr double LOCAL_BLEND_CAP = 0.25;\n        constexpr double LOCAL_BLEND_RATE = 0.03;\n        constexpr double SPLIT_DIFF_THRESH = 300.0;\n        constexpr double SPLIT_IMPROVE_RATIO = 0.05;\n        constexpr double SPLIT_IMPROVE_ABS = 20000.0;\n\n        // Horizontal rows\n        for (int i = 0; i < N; i++) {\n            const int M = N - 1; // 29\n            double W[M + 1], S[M + 1], Q[M + 1];\n            W[0] = S[0] = Q[0] = 0.0;\n            for (int j = 0; j < M; j++) {\n                double w = cnt_h[i][j];\n                double x = raw_h[i][j];\n                W[j + 1] = W[j] + w;\n                S[j + 1] = S[j] + w * x;\n                Q[j + 1] = Q[j] + w * x * x;\n            }\n\n            auto seg_mean = [&](double w, double s) -> double {\n                return (s + PRIOR_SEG_WEIGHT * PRIOR_MEAN) / (w + PRIOR_SEG_WEIGHT);\n            };\n            auto seg_sse = [&](double w, double s, double q) -> double {\n                double m = seg_mean(w, s);\n                return q - 2.0 * m * s + m * m * w;\n            };\n\n            double w_all = W[M], s_all = S[M], q_all = Q[M];\n            double mean1 = seg_mean(w_all, s_all);\n            double sse1 = seg_sse(w_all, s_all, q_all);\n\n            double best_sse2 = INF;\n            int best_split = -1;\n            double best_l = mean1, best_r = mean1;\n\n            for (int sp = 1; sp < M; sp++) {\n                double wl = W[sp], sl = S[sp], ql = Q[sp];\n                double wr = W[M] - W[sp];\n                double sr = S[M] - S[sp];\n                double qr = Q[M] - Q[sp];\n\n                double ml = seg_mean(wl, sl);\n                double mr = seg_mean(wr, sr);\n                double sse = seg_sse(wl, sl, ql) + seg_sse(wr, sr, qr);\n\n                if (sse < best_sse2) {\n                    best_sse2 = sse;\n                    best_split = sp;\n                    best_l = ml;\n                    best_r = mr;\n                }\n            }\n\n            bool use_two = false;\n            double improve = sse1 - best_sse2;\n            if (best_split != -1 &&\n                fabs(best_l - best_r) >= SPLIT_DIFF_THRESH &&\n                improve >= max(SPLIT_IMPROVE_ABS, SPLIT_IMPROVE_RATIO * sse1)) {\n                use_two = true;\n            }\n\n            for (int j = 0; j < M; j++) {\n                double target = use_two ? (j < best_split ? best_l : best_r) : mean1;\n                double alpha = min(LOCAL_BLEND_CAP, LOCAL_BLEND_RATE * cnt_h[i][j]);\n                base_h[i][j] = clamp_cost(target * (1.0 - alpha) + raw_h[i][j] * alpha);\n            }\n        }\n\n        // Vertical columns\n        for (int j = 0; j < N; j++) {\n            const int M = N - 1; // 29\n            double W[M + 1], S[M + 1], Q[M + 1];\n            W[0] = S[0] = Q[0] = 0.0;\n            for (int i = 0; i < M; i++) {\n                double w = cnt_v[i][j];\n                double x = raw_v[i][j];\n                W[i + 1] = W[i] + w;\n                S[i + 1] = S[i] + w * x;\n                Q[i + 1] = Q[i] + w * x * x;\n            }\n\n            auto seg_mean = [&](double w, double s) -> double {\n                return (s + PRIOR_SEG_WEIGHT * PRIOR_MEAN) / (w + PRIOR_SEG_WEIGHT);\n            };\n            auto seg_sse = [&](double w, double s, double q) -> double {\n                double m = seg_mean(w, s);\n                return q - 2.0 * m * s + m * m * w;\n            };\n\n            double w_all = W[M], s_all = S[M], q_all = Q[M];\n            double mean1 = seg_mean(w_all, s_all);\n            double sse1 = seg_sse(w_all, s_all, q_all);\n\n            double best_sse2 = INF;\n            int best_split = -1;\n            double best_u = mean1, best_d = mean1;\n\n            for (int sp = 1; sp < M; sp++) {\n                double wu = W[sp], su = S[sp], qu = Q[sp];\n                double wd = W[M] - W[sp];\n                double sd = S[M] - S[sp];\n                double qd = Q[M] - Q[sp];\n\n                double mu = seg_mean(wu, su);\n                double md = seg_mean(wd, sd);\n                double sse = seg_sse(wu, su, qu) + seg_sse(wd, sd, qd);\n\n                if (sse < best_sse2) {\n                    best_sse2 = sse;\n                    best_split = sp;\n                    best_u = mu;\n                    best_d = md;\n                }\n            }\n\n            bool use_two = false;\n            double improve = sse1 - best_sse2;\n            if (best_split != -1 &&\n                fabs(best_u - best_d) >= SPLIT_DIFF_THRESH &&\n                improve >= max(SPLIT_IMPROVE_ABS, SPLIT_IMPROVE_RATIO * sse1)) {\n                use_two = true;\n            }\n\n            for (int i = 0; i < M; i++) {\n                double target = use_two ? (i < best_split ? best_u : best_d) : mean1;\n                double alpha = min(LOCAL_BLEND_CAP, LOCAL_BLEND_RATE * cnt_v[i][j]);\n                base_v[i][j] = clamp_cost(target * (1.0 - alpha) + raw_v[i][j] * alpha);\n            }\n        }\n\n        // Exploration noise: large at the beginning, then decays\n        double amp = 0.0;\n        if (turn < 150) {\n            amp = 200.0 * (150 - turn) / 150.0;\n        }\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                double noise = amp * rnd_h[i][j] / sqrt(cnt_h[i][j] + 1.0);\n                search_h[i][j] = clamp_cost(base_h[i][j] + noise);\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                double noise = amp * rnd_v[i][j] / sqrt(cnt_v[i][j] + 1.0);\n                search_v[i][j] = clamp_cost(base_v[i][j] + noise);\n            }\n        }\n    }\n\n    string shortest_path(int si, int sj, int ti, int tj) {\n        const int V = N * N;\n        vector<double> dist(V, INF);\n        vector<int> par(V, -1);\n        vector<char> mv(V, 0);\n\n        auto id = [&](int x, int y) { return x * N + y; };\n\n        int s = id(si, sj);\n        int t = id(ti, tj);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == t) break;\n\n            int x = u / N;\n            int y = u % N;\n\n            auto relax = [&](int nx, int ny, double w, char c) {\n                int v = id(nx, ny);\n                double nd = d + w;\n                if (nd + 1e-12 < dist[v]) {\n                    dist[v] = nd;\n                    par[v] = u;\n                    mv[v] = c;\n                    pq.push({nd, v});\n                }\n            };\n\n            if (x > 0) relax(x - 1, y, search_v[x - 1][y], 'U');\n            if (x + 1 < N) relax(x + 1, y, search_v[x][y], 'D');\n            if (y > 0) relax(x, y - 1, search_h[x][y - 1], 'L');\n            if (y + 1 < N) relax(x, y + 1, search_h[x][y], 'R');\n        }\n\n        string path;\n        for (int cur = t; cur != s; cur = par[cur]) {\n            path.push_back(mv[cur]);\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    double path_pred_and_edges(int si, int sj, const string& path, vector<EdgeRef>& edges) {\n        edges.clear();\n        edges.reserve(path.size());\n\n        int x = si, y = sj;\n        double pred = 0.0;\n\n        for (char c : path) {\n            if (c == 'U') {\n                pred += base_v[x - 1][y];\n                edges.push_back({false, x - 1, y});\n                --x;\n            } else if (c == 'D') {\n                pred += base_v[x][y];\n                edges.push_back({false, x, y});\n                ++x;\n            } else if (c == 'L') {\n                pred += base_h[x][y - 1];\n                edges.push_back({true, x, y - 1});\n                --y;\n            } else if (c == 'R') {\n                pred += base_h[x][y];\n                edges.push_back({true, x, y});\n                ++y;\n            }\n        }\n        return pred;\n    }\n\n    void update_estimates(const vector<EdgeRef>& edges, double observed, double pred, int turn) {\n        if (edges.empty()) return;\n\n        double residual = observed - pred;\n\n        vector<double> gain(edges.size());\n        double gsum = 0.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            int c = e.horizontal ? cnt_h[e.i][e.j] : cnt_v[e.i][e.j];\n            gain[k] = 1.0 / sqrt(c + 1.0);\n            gsum += gain[k];\n        }\n\n        double eta;\n        if (turn < 80) eta = 0.55;\n        else if (turn < 250) eta = 0.40;\n        else eta = 0.30;\n\n        constexpr double DELTA_CLAMP = 1500.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            double delta = eta * residual * gain[k] / gsum;\n            delta = max(-DELTA_CLAMP, min(DELTA_CLAMP, delta));\n\n            if (e.horizontal) {\n                raw_h[e.i][e.j] = clamp_cost(raw_h[e.i][e.j] + delta);\n                cnt_h[e.i][e.j]++;\n            } else {\n                raw_v[e.i][e.j] = clamp_cost(raw_v[e.i][e.j] + delta);\n                cnt_v[e.i][e.j]++;\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(123456789) {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                raw_h[i][j] = 5000.0;\n                cnt_h[i][j] = 0;\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                raw_v[i][j] = 5000.0;\n                cnt_v[i][j] = 0;\n            }\n        }\n\n        uniform_real_distribution<double> ur(-1.0, 1.0);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                rnd_h[i][j] = ur(rng);\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                rnd_v[i][j] = ur(rng);\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int turn = 0; turn < 1000; turn++) {\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            build_model(turn);\n\n            string path = shortest_path(si, sj, ti, tj);\n\n            cout << path << endl; // flush required in interactive\n            cout.flush();\n\n            long long feedback;\n            cin >> feedback;\n\n            vector<EdgeRef> edges;\n            double pred = path_pred_and_edges(si, sj, path, edges);\n            update_estimates(edges, (double)feedback, pred, turn);\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAXL = 12;\nstatic constexpr int MINL = 2;\nstatic constexpr int MAXK = 800;\nstatic constexpr int WORDS = 13; // enough for 800 bits\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nstatic inline int ch2v(char c) { return c - 'A'; }\nstatic inline char v2ch(int v) { return char('A' + v); }\n\ntemplate<class Bits>\nstatic inline bool getbit(const Bits& b, int i) {\n    return (b[i >> 6] >> (i & 63)) & 1ULL;\n}\ntemplate<class Bits>\nstatic inline void setbit(Bits& b, int i) {\n    b[i >> 6] |= 1ULL << (i & 63);\n}\n\nstruct Pattern {\n    int len;\n    uint64_t code;\n    int weight;\n    string s;\n};\n\nstruct ACNode {\n    array<int, 8> next{};\n    int link = 0;\n    vector<int> out;\n    ACNode() { next.fill(-1); }\n};\n\nstruct State {\n    int node = 0;\n    int score = 0;\n    array<uint64_t, WORDS> seen{};\n    array<uint8_t, N> s{};\n};\n\nstruct Solver {\n    int M;\n    vector<Pattern> pats;\n    int K = 0;\n    array<unordered_map<uint64_t, int>, MAXL + 1> id_of;\n    vector<ACNode> ac;\n    vector<int> orig_weight;\n    mt19937_64 rng;\n    Timer timer;\n\n    vector<array<uint8_t, N>> rows; // selected rows\n    array<uint64_t, WORDS> base_covered{};\n    int base_score = 0;\n\n    Solver() : rng(chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    uint64_t encode_string(const string& s) {\n        uint64_t code = 0;\n        for (char c : s) code = (code << 3) | (uint64_t)ch2v(c);\n        return code;\n    }\n\n    string decode_string(uint64_t code, int len) {\n        string s(len, 'A');\n        for (int i = len - 1; i >= 0; --i) {\n            s[i] = v2ch(int(code & 7ULL));\n            code >>= 3;\n        }\n        return s;\n    }\n\n    void add_pattern_to_ac(const string& s, int id) {\n        int v = 0;\n        for (char c : s) {\n            int x = ch2v(c);\n            if (ac[v].next[x] == -1) {\n                ac[v].next[x] = (int)ac.size();\n                ac.emplace_back();\n            }\n            v = ac[v].next[x];\n        }\n        ac[v].out.push_back(id);\n    }\n\n    void build_ac() {\n        ac.clear();\n        ac.emplace_back();\n        for (int id = 0; id < K; ++id) add_pattern_to_ac(pats[id].s, id);\n\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = ac[0].next[c];\n            if (u == -1) {\n                ac[0].next[c] = 0;\n            } else {\n                ac[u].link = 0;\n                q.push(u);\n            }\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            int link = ac[v].link;\n            if (!ac[link].out.empty()) {\n                auto &dst = ac[v].out;\n                auto &src = ac[link].out;\n                dst.insert(dst.end(), src.begin(), src.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = ac[v].next[c];\n                if (u == -1) {\n                    ac[v].next[c] = ac[link].next[c];\n                } else {\n                    ac[u].link = ac[link].next[c];\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    int row_gain_and_bits(const array<uint8_t, N>& row, const vector<int>& weight,\n                          array<uint64_t, WORDS>& bits) {\n        bits.fill(0);\n        int gain = 0;\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                int v = row[(st + len - 1) % N];\n                code = (code << 3) | (uint64_t)v;\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) {\n                        int id = it->second;\n                        if (weight[id] > 0 && !getbit(bits, id)) {\n                            setbit(bits, id);\n                            gain += weight[id];\n                        }\n                    }\n                }\n            }\n        }\n        return gain;\n    }\n\n    void add_row_to_cover(const array<uint8_t, N>& row,\n                          array<uint64_t, WORDS>& covered,\n                          int& score) {\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                int v = row[(st + len - 1) % N];\n                code = (code << 3) | (uint64_t)v;\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) {\n                        int id = it->second;\n                        if (!getbit(covered, id)) {\n                            setbit(covered, id);\n                            score += orig_weight[id];\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    array<uint8_t, N> fallback_row(const vector<int>& residual) {\n        int best_id = -1, best_w = -1;\n        for (int i = 0; i < K; ++i) {\n            if (residual[i] > best_w) {\n                best_w = residual[i];\n                best_id = i;\n            }\n        }\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n        if (best_id != -1) {\n            const string& s = pats[best_id].s;\n            for (int i = 0; i < (int)s.size(); ++i) row[i] = ch2v(s[i]);\n        }\n        return row;\n    }\n\n    array<uint8_t, N> beam_search_row(const vector<int>& residual) {\n        static constexpr int BEAM = 260;\n        static constexpr int FINAL_CAND = 48;\n\n        vector<State> beam(1);\n        beam[0].node = 0;\n        beam[0].score = 0;\n        beam[0].seen.fill(0);\n\n        for (int d = 0; d < N; ++d) {\n            vector<State> cand;\n            cand.reserve(beam.size() * 8);\n            for (const auto& st : beam) {\n                for (int c = 0; c < 8; ++c) {\n                    State ns = st;\n                    ns.node = ac[st.node].next[c];\n                    ns.s[d] = (uint8_t)c;\n                    for (int id : ac[ns.node].out) {\n                        if (residual[id] > 0 && !getbit(ns.seen, id)) {\n                            setbit(ns.seen, id);\n                            ns.score += residual[id];\n                        }\n                    }\n                    cand.push_back(std::move(ns));\n                }\n            }\n\n            auto cmp = [](const State& a, const State& b) {\n                return a.score > b.score;\n            };\n            if ((int)cand.size() > BEAM) {\n                nth_element(cand.begin(), cand.begin() + BEAM, cand.end(), cmp);\n                cand.resize(BEAM);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n            beam.swap(cand);\n        }\n\n        int take = min<int>(beam.size(), FINAL_CAND);\n        int best_gain = -1;\n        array<uint8_t, N> best_row{};\n        for (int i = 0; i < take; ++i) {\n            array<uint8_t, N> row = beam[i].s;\n            array<uint64_t, WORDS> bits{};\n            int gain = row_gain_and_bits(row, residual, bits);\n            if (gain > best_gain) {\n                best_gain = gain;\n                best_row = row;\n            }\n        }\n        if (best_gain <= 0) return fallback_row(residual);\n        return best_row;\n    }\n\n    int count_residual_positive(const vector<int>& residual) {\n        int s = 0;\n        for (int x : residual) s += x;\n        return s;\n    }\n\n    int eval_horizontal_subset(const vector<int>& idxs, const vector<bool>& alive) {\n        array<uint64_t, WORDS> covered{};\n        covered.fill(0);\n        int score = 0;\n        for (int i : idxs) {\n            if (!alive[i]) continue;\n            add_row_to_cover(rows[i], covered, score);\n        }\n        return score;\n    }\n\n    int eval_total_with_layout(const vector<int>& order, const vector<int>& shift) {\n        array<uint64_t, WORDS> covered = base_covered;\n        int score = base_score;\n\n        int col[N];\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < N; ++r) {\n                col[r] = rows[order[r]][(c + shift[r]) % N];\n            }\n            for (int st = 0; st < N; ++st) {\n                uint64_t code = 0;\n                for (int len = 1; len <= MAXL; ++len) {\n                    code = (code << 3) | (uint64_t)col[(st + len - 1) % N];\n                    if (len >= MINL) {\n                        auto it = id_of[len].find(code);\n                        if (it != id_of[len].end()) {\n                            int id = it->second;\n                            if (!getbit(covered, id)) {\n                                setbit(covered, id);\n                                score += orig_weight[id];\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        return score;\n    }\n\n    vector<string> solve() {\n        int n, m;\n        cin >> n >> m;\n        M = m;\n\n        array<unordered_map<uint64_t, int>, MAXL + 1> cnt_of;\n        for (int len = MINL; len <= MAXL; ++len) cnt_of[len].reserve(M * 2);\n\n        for (int i = 0; i < M; ++i) {\n            string s;\n            cin >> s;\n            uint64_t code = encode_string(s);\n            cnt_of[(int)s.size()][code]++;\n        }\n\n        pats.clear();\n        for (int len = MINL; len <= MAXL; ++len) {\n            id_of[len].clear();\n            id_of[len].reserve(cnt_of[len].size() * 2 + 1);\n            for (auto &kv : cnt_of[len]) {\n                Pattern p;\n                p.len = len;\n                p.code = kv.first;\n                p.weight = kv.second;\n                p.s = decode_string(kv.first, len);\n                int id = (int)pats.size();\n                pats.push_back(std::move(p));\n                id_of[len][kv.first] = id;\n            }\n        }\n        K = (int)pats.size();\n\n        orig_weight.assign(K, 0);\n        for (int i = 0; i < K; ++i) orig_weight[i] = pats[i].weight;\n\n        build_ac();\n\n        rows.clear();\n        base_covered.fill(0);\n        base_score = 0;\n\n        vector<int> residual = orig_weight;\n        for (int r = 0; r < N; ++r) {\n            if (count_residual_positive(residual) == 0) break;\n\n            array<uint8_t, N> row = beam_search_row(residual);\n\n            array<uint64_t, WORDS> bits{};\n            int gain = row_gain_and_bits(row, residual, bits);\n\n            // very rare fallback\n            if (gain == 0) {\n                row = fallback_row(residual);\n                gain = row_gain_and_bits(row, residual, bits);\n            }\n\n            rows.push_back(row);\n\n            for (int id = 0; id < K; ++id) {\n                if (getbit(bits, id)) {\n                    residual[id] = 0;\n                    if (!getbit(base_covered, id)) {\n                        setbit(base_covered, id);\n                        base_score += orig_weight[id];\n                    }\n                }\n            }\n        }\n\n        // If already all covered horizontally, try to remove redundant rows and use '.' rows.\n        if (base_score == M) {\n            vector<bool> alive(rows.size(), true);\n            vector<int> idxs(rows.size());\n            iota(idxs.begin(), idxs.end(), 0);\n            for (int i = 0; i < (int)rows.size(); ++i) {\n                alive[i] = false;\n                if (eval_horizontal_subset(idxs, alive) != M) alive[i] = true;\n            }\n\n            vector<string> ans;\n            for (int i = 0; i < (int)rows.size(); ++i) if (alive[i]) {\n                string s(N, 'A');\n                for (int j = 0; j < N; ++j) s[j] = v2ch(rows[i][j]);\n                ans.push_back(s);\n            }\n            while ((int)ans.size() < N) ans.push_back(string(N, '.'));\n            return ans;\n        }\n\n        // Fill remaining rows with random rows if necessary.\n        while ((int)rows.size() < N) {\n            array<uint8_t, N> row{};\n            for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n            rows.push_back(row);\n        }\n\n        // Local search on row order / rotation to gain vertical matches.\n        vector<int> order(N), shift(N, 0);\n        iota(order.begin(), order.end(), 0);\n\n        int cur = eval_total_with_layout(order, shift);\n        int best = cur;\n        vector<int> best_order = order, best_shift = shift;\n\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        const double time_limit = 2.85;\n        while (timer.elapsed() < time_limit) {\n            double prog = min(1.0, timer.elapsed() / time_limit);\n            double T = 3.0 * pow(0.02 / 3.0, prog);\n\n            bool type = (rng() % 100) < 70; // shift move more often\n            if (type) {\n                int r = (int)(rng() % N);\n                int old = shift[r];\n                int nw = (int)(rng() % N);\n                if (nw == old) continue;\n                shift[r] = nw;\n                int nxt = eval_total_with_layout(order, shift);\n                int diff = nxt - cur;\n                if (diff >= 0 || urd(rng) < exp(diff / T)) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        best_order = order;\n                        best_shift = shift;\n                    }\n                } else {\n                    shift[r] = old;\n                }\n            } else {\n                int a = (int)(rng() % N);\n                int b = (int)(rng() % N);\n                if (a == b) continue;\n                swap(order[a], order[b]);\n                swap(shift[a], shift[b]);\n                int nxt = eval_total_with_layout(order, shift);\n                int diff = nxt - cur;\n                if (diff >= 0 || urd(rng) < exp(diff / T)) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        best_order = order;\n                        best_shift = shift;\n                    }\n                } else {\n                    swap(order[a], order[b]);\n                    swap(shift[a], shift[b]);\n                }\n            }\n        }\n\n        vector<string> ans(N, string(N, 'A'));\n        for (int r = 0; r < N; ++r) {\n            int id = best_order[r];\n            for (int c = 0; c < N; ++c) {\n                ans[r][c] = v2ch(rows[id][(c + best_shift[r]) % N]);\n            }\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    auto ans = solver.solve();\n    for (auto &s : ans) cout << s << '\\n';\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF = (1LL << 60);\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp() {}\n    HopcroftKarp(int nL, int nR) : nL(nL), nR(nR), g(nL), pairU(nL, -1), pairV(nR, -1) {}\n\n    void add_edge(int u, int v) {\n        g[u].push_back(v);\n    }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        bool found = false;\n        for (int u = 0; u < nL; u++) {\n            if (pairU[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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        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        // Assumes max_matching() already called.\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();\n            q.pop();\n            for (int v : g[u]) {\n                if (pairU[u] == v) continue; // only unmatched edges L->R\n                if (!visR[v]) {\n                    visR[v] = 1;\n                    int pu = pairV[v];\n                    if (pu != -1 && !visL[pu]) {\n                        visL[pu] = 1;\n                        q.push(pu);\n                    }\n                }\n            }\n        }\n        vector<char> inL(nL, 0), inR(nR, 0);\n        for (int u = 0; u < nL; u++) inL[u] = !visL[u];\n        for (int v = 0; v < nR; v++) inR[v] = visR[v];\n        return {inL, inR};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    cin >> N >> si >> sj;\n    vector<string> c(N);\n    for (int i = 0; i < N; i++) cin >> c[i];\n\n    vector<vector<int>> cellId(N, vector<int>(N, -1));\n    vector<int> rr, cc, enterCost;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (c[i][j] != '#') {\n                cellId[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                enterCost.push_back(c[i][j] - '0');\n            }\n        }\n    }\n    int M = (int)rr.size();\n    int startCell = cellId[si][sj];\n\n    vector<vector<int>> nbr(M);\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (0 <= ni && ni < N && 0 <= nj && nj < N && cellId[ni][nj] != -1) {\n                nbr[id].push_back(cellId[ni][nj]);\n            }\n        }\n    }\n\n    auto dijkstra = [&](int src, bool reverse, bool needPrev) {\n        vector<ll> dist(M, INF);\n        vector<int> prev(needPrev ? M : 0, -1);\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n        while (!pq.empty()) {\n            auto [cd, u] = pq.top();\n            pq.pop();\n            if (cd != dist[u]) continue;\n            for (int v : nbr[u]) {\n                ll w = reverse ? enterCost[u] : enterCost[v];\n                ll nd = cd + w;\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (needPrev) prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n        return make_pair(dist, prev);\n    };\n\n    auto [distFromStart, dummyPrev1] = dijkstra(startCell, false, false);\n    auto [distToStart, dummyPrev2] = dijkstra(startCell, true, false);\n\n    // Segment decomposition\n    vector<vector<int>> hSeg(N, vector<int>(N, -1));\n    vector<vector<int>> vSeg(N, vector<int>(N, -1));\n    int Hcnt = 0, Vcnt = 0;\n\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (c[i][j] == '#') {\n                j++;\n                continue;\n            }\n            int k = j;\n            while (k < N && c[i][k] != '#') {\n                hSeg[i][k] = Hcnt;\n                k++;\n            }\n            Hcnt++;\n            j = k;\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (c[i][j] == '#') {\n                i++;\n                continue;\n            }\n            int k = i;\n            while (k < N && c[k][j] != '#') {\n                vSeg[k][j] = Vcnt;\n                k++;\n            }\n            Vcnt++;\n            i = k;\n        }\n    }\n\n    vector<int> cellH(M), cellV(M);\n    vector<vector<int>> adjV(Hcnt), adjCellH(Hcnt);\n    vector<vector<int>> adjH(Vcnt), adjCellV(Vcnt);\n\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        int h = hSeg[i][j];\n        int v = vSeg[i][j];\n        cellH[id] = h;\n        cellV[id] = v;\n        adjV[h].push_back(v);\n        adjCellH[h].push_back(id);\n        adjH[v].push_back(h);\n        adjCellV[v].push_back(id);\n    }\n\n    auto findCellHV = [&](int h, int v) -> int {\n        for (int k = 0; k < (int)adjV[h].size(); k++) {\n            if (adjV[h][k] == v) return adjCellH[h][k];\n        }\n        return -1;\n    };\n\n    // Minimum vertex cover on segment bipartite graph\n    HopcroftKarp hk(Hcnt, Vcnt);\n    for (int h = 0; h < Hcnt; h++) {\n        for (int v : adjV[h]) hk.add_edge(h, v);\n    }\n    hk.max_matching();\n    auto [selH, selV] = hk.min_vertex_cover();\n\n    int startH = cellH[startCell];\n    int startV = cellV[startCell];\n\n    vector<char> needH = selH, needV = selV;\n    if (needH[startH]) needH[startH] = 0; // already activated by start\n    if (needV[startV]) needV[startV] = 0;\n\n    // Pair selected segments as much as possible\n    vector<int> mapH(Hcnt, -1), revH;\n    vector<int> mapV(Vcnt, -1), revV;\n    for (int h = 0; h < Hcnt; h++) {\n        if (needH[h]) {\n            mapH[h] = (int)revH.size();\n            revH.push_back(h);\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (needV[v]) {\n            mapV[v] = (int)revV.size();\n            revV.push_back(v);\n        }\n    }\n\n    HopcroftKarp hk2((int)revH.size(), (int)revV.size());\n    for (int ih = 0; ih < (int)revH.size(); ih++) {\n        int h = revH[ih];\n        for (int k = 0; k < (int)adjV[h].size(); k++) {\n            int v = adjV[h][k];\n            if (mapV[v] != -1) hk2.add_edge(ih, mapV[v]);\n        }\n    }\n    hk2.max_matching();\n\n    vector<char> chosenCell(M, 0);\n\n    // Matched selected-selected edges\n    for (int ih = 0; ih < (int)revH.size(); ih++) {\n        int jv = hk2.pairU[ih];\n        if (jv != -1) {\n            int h = revH[ih];\n            int v = revV[jv];\n            int cell = findCellHV(h, v);\n            if (cell != -1) chosenCell[cell] = 1;\n        }\n    }\n\n    auto cellScore = [&](int cell) -> ll {\n        return distFromStart[cell] + distToStart[cell];\n    };\n\n    auto chooseBestCellForH = [&](int h) -> int {\n        int best = -1;\n        ll bestScore = INF;\n        for (int cell : adjCellH[h]) {\n            ll sc = cellScore(cell);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = cell;\n            }\n        }\n        return best;\n    };\n    auto chooseBestCellForV = [&](int v) -> int {\n        int best = -1;\n        ll bestScore = INF;\n        for (int cell : adjCellV[v]) {\n            ll sc = cellScore(cell);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = cell;\n            }\n        }\n        return best;\n    };\n\n    // Unmatched selected H\n    for (int ih = 0; ih < (int)revH.size(); ih++) {\n        if (hk2.pairU[ih] == -1) {\n            int h = revH[ih];\n            int cell = chooseBestCellForH(h);\n            if (cell != -1) chosenCell[cell] = 1;\n        }\n    }\n    // Unmatched selected V\n    for (int jv = 0; jv < (int)revV.size(); jv++) {\n        if (hk2.pairV[jv] == -1) {\n            int v = revV[jv];\n            int cell = chooseBestCellForV(v);\n            if (cell != -1) chosenCell[cell] = 1;\n        }\n    }\n\n    vector<int> relCells;\n    relCells.push_back(startCell);\n    vector<int> extra;\n    for (int cell = 0; cell < M; cell++) {\n        if (chosenCell[cell] && cell != startCell) extra.push_back(cell);\n    }\n    sort(extra.begin(), extra.end(), [&](int a, int b) {\n        ll sa = cellScore(a), sb = cellScore(b);\n        if (sa != sb) return sa < sb;\n        if (rr[a] != rr[b]) return rr[a] < rr[b];\n        return cc[a] < cc[b];\n    });\n    for (int cell : extra) relCells.push_back(cell);\n\n    int R = (int)relCells.size();\n\n    vector<vector<ll>> distMat(R, vector<ll>(R, INF));\n    vector<vector<int>> prevs(R, vector<int>(M, -1));\n\n    for (int s = 0; s < R; s++) {\n        auto [dist, prev] = dijkstra(relCells[s], false, true);\n        prevs[s] = move(prev);\n        for (int t = 0; t < R; t++) {\n            distMat[s][t] = dist[relCells[t]];\n        }\n    }\n\n    vector<int> cycle;\n    if (R == 1) {\n        cycle = {0};\n    } else {\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestInit = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll val = distMat[0][i] + distMat[i][0];\n            if (val < bestInit) {\n                bestInit = val;\n                first = i;\n            }\n        }\n        cycle = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            ll bestDelta = INF;\n            int bestNode = -1, bestPos = -1;\n            int sz = (int)cycle.size();\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                for (int pos = 0; pos < sz; pos++) {\n                    int a = cycle[pos];\n                    int b = cycle[(pos + 1) % sz];\n                    ll delta = distMat[a][x] + distMat[x][b] - distMat[a][b];\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestNode = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            used[bestNode] = 1;\n            cycle.insert(cycle.begin() + bestPos + 1, bestNode);\n        }\n\n        // Small relocate local search\n        for (int iter = 0; iter < 5000; iter++) {\n            bool improved = false;\n            int sz = (int)cycle.size();\n            for (int i = 1; i < sz && !improved; i++) {\n                int a = cycle[(i - 1 + sz) % sz];\n                int x = cycle[i];\n                int b = cycle[(i + 1) % sz];\n                ll removeDelta = distMat[a][b] - distMat[a][x] - distMat[x][b];\n\n                for (int j = 0; j < sz && !improved; j++) {\n                    if (j == i || j == (i - 1 + sz) % sz) continue;\n                    int c1 = cycle[j];\n                    int d1 = cycle[(j + 1) % sz];\n                    ll delta = removeDelta + distMat[c1][x] + distMat[x][d1] - distMat[c1][d1];\n                    if (delta < 0) {\n                        cycle.erase(cycle.begin() + i);\n                        if (j > i) j--;\n                        cycle.insert(cycle.begin() + j + 1, x);\n                        improved = true;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    auto dirChar = [&](int a, int b) -> char {\n        int ra = rr[a], ca = cc[a];\n        int rb = rr[b], cb = cc[b];\n        if (rb == ra - 1 && cb == ca) return 'U';\n        if (rb == ra + 1 && cb == ca) return 'D';\n        if (rb == ra && cb == ca - 1) return 'L';\n        return 'R';\n    };\n\n    string ans;\n    for (int idx = 0; idx < (int)cycle.size(); idx++) {\n        int sIdx = cycle[idx];\n        int tIdx = cycle[(idx + 1) % cycle.size()];\n        int sCell = relCells[sIdx];\n        int tCell = relCells[tIdx];\n        if (sCell == tCell) continue;\n\n        vector<int> pathRev;\n        int cur = tCell;\n        while (cur != sCell) {\n            int p = prevs[sIdx][cur];\n            if (p == -1) {\n                // Should not happen on connected road component.\n                break;\n            }\n            pathRev.push_back(cur);\n            cur = p;\n        }\n        reverse(pathRev.begin(), pathRev.end());\n\n        int curCell = sCell;\n        for (int nxt : pathRev) {\n            ans.push_back(dirChar(curCell, nxt));\n            curCell = nxt;\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 1000;\n\nstruct Observation {\n    int task;\n    int t;\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>> children(N), parents(N);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        children[u].push_back(v);\n        parents[v].push_back(u);\n    }\n\n    // ----------------------------\n    // Precompute task statistics\n    // ----------------------------\n    vector<int> indeg(N), rem_pre(N);\n    vector<int> sumd(N, 0), outdeg(N, 0);\n    vector<int> maxd(K, 0);\n    vector<double> avgd(K, 0.0);\n\n    for (int i = 0; i < N; ++i) {\n        indeg[i] = (int)parents[i].size();\n        rem_pre[i] = indeg[i];\n        outdeg[i] = (int)children[i].size();\n        for (int k = 0; k < K; ++k) {\n            sumd[i] += d[i][k];\n            maxd[k] = max(maxd[k], d[i][k]);\n            avgd[k] += d[i][k];\n        }\n    }\n    for (int k = 0; k < K; ++k) avgd[k] /= N;\n\n    // Initial skill guess: member skill norm is larger than task norm on average.\n    vector<int> init_skill(K);\n    for (int k = 0; k < K; ++k) {\n        int v = (int)llround(avgd[k] * 1.6);\n        v = max(0, min(v, maxd[k]));\n        init_skill[k] = v;\n    }\n\n    // Descendant count by bitset DP\n    vector<bitset<MAXN>> reach(N);\n    vector<int> desc_cnt(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        for (int ch : children[i]) {\n            reach[i] |= reach[ch];\n            reach[i].set(ch);\n        }\n        desc_cnt[i] = (int)reach[i].count();\n    }\n\n    // Weighted bottom level\n    vector<long long> bottom(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        long long best_child = 0;\n        for (int ch : children[i]) best_child = max(best_child, bottom[ch]);\n        long long node_w = sumd[i] + 5;\n        bottom[i] = node_w + best_child;\n    }\n\n    vector<long long> priority(N, 0);\n    for (int i = 0; i < N; ++i) {\n        // Tuned static priority:\n        // critical path weight + descendant count + direct unlock count + task size\n        priority[i] = bottom[i] * 30LL + desc_cnt[i] * 5LL + outdeg[i] * 20LL + sumd[i];\n    }\n\n    auto calc_w_with_skill = [&](int task, const vector<int>& skill) -> int {\n        int w = 0;\n        for (int k = 0; k < K; ++k) {\n            if (d[task][k] > skill[k]) w += d[task][k] - skill[k];\n        }\n        return w;\n    };\n\n    vector<int> default_w(N), default_t(N);\n    for (int i = 0; i < N; ++i) {\n        default_w[i] = calc_w_with_skill(i, init_skill);\n        default_t[i] = max(1, default_w[i]);\n    }\n\n    // ----------------------------\n    // Online state\n    // ----------------------------\n    // task_status: -1 = not started, 0 = in progress, 1 = completed\n    vector<int> task_status(N, -1);\n\n    // member current task\n    vector<int> current_task(M, -1);\n    vector<int> start_day(M, -1);\n\n    // estimated skills\n    vector<vector<int>> skill_hat(M, init_skill);\n    vector<vector<Observation>> obs(M);\n\n    auto loss_interval = [&](int w, int t) -> double {\n        int L, U;\n        if (t <= 1) {\n            L = 0;\n            U = 3;\n        } else {\n            L = max(0, t - 3);\n            U = t + 3;\n        }\n        double dist = 0.0;\n        if (w < L) dist = (double)(L - w);\n        else if (w > U) dist = (double)(w - U);\n        else dist = 0.0;\n\n        double weight = (t <= 1 ? 1.0 : 1.0 + 0.05 * min(t, 20));\n        return dist * dist * weight;\n    };\n\n    auto optimize_member = [&](int j) {\n        int T = (int)obs[j].size();\n        if (T == 0) return;\n\n        vector<int>& s = skill_hat[j];\n        vector<int> curW(T);\n        for (int idx = 0; idx < T; ++idx) {\n            curW[idx] = calc_w_with_skill(obs[j][idx].task, s);\n        }\n\n        int max_iter = 3;\n        for (int it = 0; it < max_iter; ++it) {\n            bool changed = false;\n\n            for (int k = 0; k < K; ++k) {\n                int prev = s[k];\n\n                vector<int> base(T);\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    base[idx] = curW[idx] - max(0, d[task][k] - prev);\n                }\n\n                double best_obj = 1e100;\n                int best_x = prev;\n                int best_tie1 = 0;\n                int best_tie2 = abs(prev - init_skill[k]);\n\n                for (int x = 0; x <= maxd[k]; ++x) {\n                    double obj = 0.0;\n                    for (int idx = 0; idx < T; ++idx) {\n                        int task = obs[j][idx].task;\n                        int w = base[idx] + max(0, d[task][k] - x);\n                        obj += loss_interval(w, obs[j][idx].t);\n                    }\n\n                    int tie1 = abs(x - prev);\n                    int tie2 = abs(x - init_skill[k]);\n                    if (obj + 1e-9 < best_obj ||\n                        (abs(obj - best_obj) <= 1e-9 &&\n                         (tie1 < best_tie1 || (tie1 == best_tie1 && tie2 < best_tie2)))) {\n                        best_obj = obj;\n                        best_x = x;\n                        best_tie1 = tie1;\n                        best_tie2 = tie2;\n                    }\n                }\n\n                if (best_x != prev) changed = true;\n                s[k] = best_x;\n\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    curW[idx] = base[idx] + max(0, d[task][k] - best_x);\n                }\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto estimate_time = [&](int member, int task) -> double {\n        // Blend default estimate and learned estimate based on observation count.\n        double trust = (double)obs[member].size() / ((double)obs[member].size() + 5.0);\n        int learned_w = calc_w_with_skill(task, skill_hat[member]);\n        double p = (1.0 - trust) * default_w[task] + trust * learned_w;\n        return max(1.0, p);\n    };\n\n    auto get_ready_tasks = [&]() -> vector<int> {\n        vector<int> ready;\n        ready.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (task_status[i] == -1 && rem_pre[i] == 0) ready.push_back(i);\n        }\n        return ready;\n    };\n\n    auto select_candidates = [&](const vector<int>& ready, int free_cnt) -> vector<int> {\n        if ((int)ready.size() <= max(60, free_cnt * 5)) return ready;\n\n        int take_priority = max(20, free_cnt * 3);\n        int take_easy = max(10, free_cnt * 2);\n\n        vector<int> by_pri = ready;\n        sort(by_pri.begin(), by_pri.end(), [&](int a, int b) {\n            if (priority[a] != priority[b]) return priority[a] > priority[b];\n            return a < b;\n        });\n\n        vector<int> by_easy = ready;\n        sort(by_easy.begin(), by_easy.end(), [&](int a, int b) {\n            if (default_t[a] != default_t[b]) return default_t[a] < default_t[b];\n            if (priority[a] != priority[b]) return priority[a] > priority[b];\n            return a < b;\n        });\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(take_priority + take_easy);\n\n        for (int i = 0; i < (int)by_pri.size() && (int)cand.size() < take_priority; ++i) {\n            int t = by_pri[i];\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_easy.size() && i < take_easy; ++i) {\n            int t = by_easy[i];\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        // Ensure enough candidates\n        for (int t : by_pri) {\n            if ((int)cand.size() >= max(30, free_cnt * 5)) break;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        return cand;\n    };\n\n    auto decide_assignments = [&]() -> vector<pair<int,int>> {\n        vector<int> free_members;\n        for (int j = 0; j < M; ++j) {\n            if (current_task[j] == -1) free_members.push_back(j);\n        }\n\n        vector<int> ready = get_ready_tasks();\n        if (free_members.empty() || ready.empty()) return {};\n\n        vector<int> cand = select_candidates(ready, (int)free_members.size());\n        int F = (int)free_members.size();\n        int C = (int)cand.size();\n\n        const long long TIME_PENALTY = 800;  // tuned balance\n\n        vector<vector<long long>> score(F, vector<long long>(C));\n        for (int fi = 0; fi < F; ++fi) {\n            int mem = free_members[fi];\n            for (int ci = 0; ci < C; ++ci) {\n                int task = cand[ci];\n                double et = estimate_time(mem, task);\n                score[fi][ci] = priority[task] - (long long)llround(et * TIME_PENALTY);\n            }\n        }\n\n        vector<char> used_f(F, 0), used_c(C, 0);\n        vector<pair<int,int>> ret;\n        int rounds = min(F, C);\n\n        for (int step = 0; step < rounds; ++step) {\n            long long best_score = LLONG_MIN;\n            int best_f = -1, best_c = -1;\n            for (int fi = 0; fi < F; ++fi) if (!used_f[fi]) {\n                for (int ci = 0; ci < C; ++ci) if (!used_c[ci]) {\n                    if (score[fi][ci] > best_score) {\n                        best_score = score[fi][ci];\n                        best_f = fi;\n                        best_c = ci;\n                    }\n                }\n            }\n            if (best_f == -1) break;\n            used_f[best_f] = 1;\n            used_c[best_c] = 1;\n            ret.emplace_back(free_members[best_f], cand[best_c]);\n        }\n        return ret;\n    };\n\n    // ----------------------------\n    // Interactive loop\n    // ----------------------------\n    int day = 0;\n    while (true) {\n        ++day;\n\n        vector<pair<int,int>> assigns = decide_assignments();\n\n        // Apply assignment to local state before reading today's completion.\n        for (auto [mem, task] : assigns) {\n            task_status[task] = 0;\n            current_task[mem] = task;\n            start_day[mem] = day;\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        int nfin;\n        cin >> nfin;\n        if (!cin) return 0;\n        if (nfin == -1) {\n            return 0;\n        }\n\n        vector<int> finished(nfin);\n        for (int i = 0; i < nfin; ++i) {\n            cin >> finished[i];\n            --finished[i];\n        }\n\n        // Process completions at end of day\n        for (int mem : finished) {\n            int task = current_task[mem];\n            if (task == -1) continue; // safety\n\n            int duration = day - start_day[mem] + 1;\n            obs[mem].push_back({task, duration});\n\n            task_status[task] = 1;\n            current_task[mem] = -1;\n            start_day[mem] = -1;\n\n            for (int ch : children[task]) {\n                --rem_pre[ch];\n            }\n\n            optimize_member(mem);\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 1000;\nstatic constexpr int TOT = 2001; // 0: office, 1..1000: pickup, 1001..2000: delivery\nstatic constexpr double TL = 1.95;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        auto ed = chrono::steady_clock::now();\n        return chrono::duration<double>(ed - st).count();\n    }\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Insertion {\n    int delta;\n    int g1, g2;\n};\n\nstruct State {\n    vector<int> seq;       // node indices\n    vector<char> selected; // 1..1000\n    int cost = 0;\n};\n\nint X[TOT], Y[TOT];\nvector<int> DM; // flat distance matrix\nint baseKey[N + 1];\n\ninline int dist_node(int a, int b) {\n    return DM[a * TOT + b];\n}\n\ninline int pickup_node(int id) { return id; }\ninline int delivery_node(int id) { return N + id; }\n\nint route_cost(const vector<int>& seq) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)seq.size(); i++) s += dist_node(seq[i], seq[i + 1]);\n    return s;\n}\n\nInsertion find_best_insertion(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    const int m = (int)seq.size();\n\n    Insertion best{INT_MAX, -1, -1};\n\n    for (int g1 = 0; g1 < m - 1; g1++) {\n        int a = seq[g1], b = seq[g1 + 1];\n        int dab = dist_node(a, b);\n\n        int delta_pick = dist_node(a, u) + dist_node(u, b) - dab;\n\n        // same gap: a - u - v - b\n        int delta_same = dist_node(a, u) + dist_node(u, v) + dist_node(v, b) - dab;\n        if (delta_same < best.delta ||\n            (delta_same == best.delta && baseKey[id] < baseKey[(best.g1 == -1 ? id : id)])) {\n            best = {delta_same, g1, g1};\n        }\n\n        // different gap\n        for (int g2 = g1 + 1; g2 < m - 1; g2++) {\n            int c = seq[g2], d = seq[g2 + 1];\n            int delta = delta_pick + dist_node(c, v) + dist_node(v, d) - dist_node(c, d);\n            if (delta < best.delta) {\n                best = {delta, g1, g2};\n            }\n        }\n    }\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& seq, int id, const Insertion& ins) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() + 2);\n\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == ins.g1) {\n            res.push_back(u);\n            if (ins.g2 == ins.g1) res.push_back(v);\n        }\n        if (i == ins.g2 && ins.g2 > ins.g1) {\n            res.push_back(v);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() - 2);\n    for (int x : seq) {\n        if (x != u && x != v) res.push_back(x);\n    }\n    return res;\n}\n\nState construct_solution(bool randomized, XorShift64& rng) {\n    State st;\n    st.seq = {0, 0};\n    st.selected.assign(N + 1, 0);\n    st.cost = 0;\n\n    constexpr int TOPK = 4;\n\n    for (int step = 0; step < 50; step++) {\n        struct Cand {\n            int delta;\n            int id;\n            Insertion ins;\n        };\n        vector<Cand> top;\n        top.reserve(TOPK);\n\n        for (int id = 1; id <= N; id++) {\n            if (st.selected[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            Cand c{ins.delta, id, ins};\n\n            if ((int)top.size() < TOPK) {\n                top.push_back(c);\n                sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                    if (a.delta != b.delta) return a.delta < b.delta;\n                    return baseKey[a.id] < baseKey[b.id];\n                });\n            } else {\n                auto worse = top.back();\n                if (c.delta < worse.delta || (c.delta == worse.delta && baseKey[c.id] < baseKey[worse.id])) {\n                    top.back() = c;\n                    sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                        if (a.delta != b.delta) return a.delta < b.delta;\n                        return baseKey[a.id] < baseKey[b.id];\n                    });\n                }\n            }\n        }\n\n        int idx = 0;\n        if (randomized && !top.empty()) {\n            int r = rng.next_int(0, 99);\n            if ((int)top.size() >= 4) {\n                if (r < 50) idx = 0;\n                else if (r < 75) idx = 1;\n                else if (r < 90) idx = 2;\n                else idx = 3;\n            } else if ((int)top.size() == 3) {\n                if (r < 55) idx = 0;\n                else if (r < 85) idx = 1;\n                else idx = 2;\n            } else if ((int)top.size() == 2) {\n                idx = (r < 70 ? 0 : 1);\n            } else {\n                idx = 0;\n            }\n        }\n\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n    }\n\n    return st;\n}\n\nvoid improve_route_relocate(State& st, const Timer& timer, double end_time, int max_passes = 100) {\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_new_cost = st.cost;\n        int best_id = -1;\n        Insertion best_ins;\n        vector<int> best_removed_seq;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int cost_removed = route_cost(seq_removed);\n            Insertion ins = find_best_insertion(seq_removed, id);\n            int new_cost = cost_removed + ins.delta;\n\n            if (new_cost < best_new_cost) {\n                best_new_cost = new_cost;\n                best_id = id;\n                best_ins = ins;\n                best_removed_seq = move(seq_removed);\n            }\n        }\n\n        if (best_id == -1) break;\n        st.seq = apply_insertion(best_removed_seq, best_id, best_ins);\n        st.cost = best_new_cost;\n    }\n}\n\nvoid improve_swap(State& st, const Timer& timer, double end_time) {\n    constexpr int TOP_REMOVE = 8;\n    constexpr int TOP_ADD = 40;\n\n    while (timer.elapsed() < end_time) {\n        struct RemCand {\n            int gain;\n            int id;\n            int removed_cost;\n        };\n        vector<RemCand> rems;\n        rems.reserve(50);\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int removed_cost = route_cost(seq_removed);\n            int gain = st.cost - removed_cost;\n            rems.push_back({gain, id, removed_cost});\n        }\n\n        sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.id < b.id;\n        });\n        if ((int)rems.size() > TOP_REMOVE) rems.resize(TOP_REMOVE);\n\n        struct AddCand {\n            int delta;\n            int id;\n        };\n        vector<AddCand> adds;\n        adds.reserve(N - 50);\n\n        for (int id = 1; id <= N; id++) {\n            if (st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n            Insertion ins = find_best_insertion(st.seq, id);\n            adds.push_back({ins.delta, id});\n        }\n\n        sort(adds.begin(), adds.end(), [](const AddCand& a, const AddCand& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            return baseKey[a.id] < baseKey[b.id];\n        });\n        if ((int)adds.size() > TOP_ADD) adds.resize(TOP_ADD);\n\n        int best_new_cost = st.cost;\n        int best_remove = -1, best_add = -1;\n        Insertion best_ins;\n        vector<int> best_removed_seq;\n\n        for (const auto& rc : rems) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> seq_removed = remove_order(st.seq, rc.id);\n            int cost_removed = route_cost(seq_removed);\n\n            for (const auto& ac : adds) {\n                Insertion ins = find_best_insertion(seq_removed, ac.id);\n                int new_cost = cost_removed + ins.delta;\n                if (new_cost < best_new_cost) {\n                    best_new_cost = new_cost;\n                    best_remove = rc.id;\n                    best_add = ac.id;\n                    best_ins = ins;\n                    best_removed_seq = seq_removed;\n                }\n            }\n        }\n\n        if (best_remove == -1) break;\n\n        st.selected[best_remove] = 0;\n        st.selected[best_add] = 1;\n        st.seq = apply_insertion(best_removed_seq, best_add, best_ins);\n        st.cost = best_new_cost;\n\n        improve_route_relocate(st, timer, end_time, 2);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // node 0 = office\n    X[0] = 400;\n    Y[0] = 400;\n\n    long long seed = 123456789;\n\n    for (int i = 1; i <= N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        X[i] = a;\n        Y[i] = b;\n        X[N + i] = c;\n        Y[N + i] = d;\n\n        baseKey[i] = abs(400 - a) + abs(400 - b) + abs(a - c) + abs(b - d) + abs(c - 400) + abs(d - 400);\n        seed = seed * 1000003 + a * 911 + b * 3571 + c * 1021 + d;\n    }\n\n    DM.assign(TOT * TOT, 0);\n    for (int i = 0; i < TOT; i++) {\n        for (int j = 0; j < TOT; j++) {\n            DM[i * TOT + j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n        }\n    }\n\n    Timer timer;\n    XorShift64 rng((uint64_t)seed);\n\n    State best;\n    bool has_best = false;\n\n    // Multi-start construction\n    for (int attempt = 0; attempt < 3; attempt++) {\n        if (timer.elapsed() > 0.45) break;\n\n        bool randomized = (attempt > 0);\n        State st = construct_solution(randomized, rng);\n        improve_route_relocate(st, timer, min(0.70, TL), 1);\n\n        if (!has_best || st.cost < best.cost) {\n            best = move(st);\n            has_best = true;\n        }\n    }\n\n    if (!has_best) {\n        best = construct_solution(false, rng);\n    }\n\n    // Main improvement\n    improve_route_relocate(best, timer, TL, 100);\n    improve_swap(best, timer, TL);\n    improve_route_relocate(best, timer, TL, 100);\n\n    // Output selected ids\n    vector<int> ids;\n    ids.reserve(50);\n    for (int id = 1; id <= N; id++) {\n        if (best.selected[id]) ids.push_back(id);\n    }\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.seq.size();\n    for (int node : best.seq) {\n        cout << ' ' << X[node] << ' ' << Y[node];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n, comps;\n    vector<int> p, sz;\n\n    DSU(int n = 0) : n(n), comps(n), p(n), sz(n, 1) {\n        iota(p.begin(), p.end(), 0);\n    }\n\n    int leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    int leader_const(int x) const {\n        while (p[x] != x) x = p[x];\n        return x;\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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        --comps;\n        return true;\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr double INF = 1e100;\n\nstruct Edge {\n    int u, v;\n    int d;\n};\n\ndouble estimate_completion_cost(\n    const DSU& base,\n    int next_idx,\n    double coef,\n    const vector<Edge>& edges,\n    const vector<int>& ord\n) {\n    vector<int> root_to_id(N, -1);\n    vector<int> cid(N, -1);\n    int K = 0;\n    for (int v = 0; v < N; ++v) {\n        int r = base.leader_const(v);\n        if (root_to_id[r] == -1) root_to_id[r] = K++;\n        cid[v] = root_to_id[r];\n    }\n\n    if (K == 1) return 0.0;\n\n    DSU dsu(K);\n    int need = K - 1;\n    double cost = 0.0;\n\n    for (int idx : ord) {\n        if (idx < next_idx) continue;\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n        if (dsu.merge(a, b)) {\n            cost += coef * edges[idx].d;\n            if (--need == 0) return cost;\n        }\n    }\n\n    return INF;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int,int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = pos[u].first - pos[v].first;\n        long long dy = pos[u].second - pos[v].second;\n        int d = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    DSU accepted(N);\n\n    for (int i = 0; i < M; ++i) {\n        int l;\n        cin >> l;\n\n        int u = edges[i].u;\n        int v = edges[i].v;\n\n        int ans = 0;\n\n        if (!accepted.same(u, v)) {\n            double rem_ratio = double(M - 1 - i) / double(M - 1); // 1 -> 0\n            double expected_choices = max(1.0, 5.0 * rem_ratio);\n            double base_coef = 1.0 + 2.0 / (expected_choices + 1.0);\n            double coef = min(2.0, 1.10 * base_coef);\n\n            double reject_cost = estimate_completion_cost(accepted, i + 1, coef, edges, ord);\n\n            DSU with_edge = accepted;\n            with_edge.merge(u, v);\n            double adopt_cost = l + estimate_completion_cost(with_edge, i + 1, coef, edges, ord);\n\n            if (adopt_cost <= reject_cost) {\n                ans = 1;\n                accepted.merge(u, v);\n            }\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n    bool operator==(const Pos& other) const { return x == other.x && y == other.y; }\n    bool operator!=(const Pos& other) const { return !(*this == other); }\n};\n\nstatic const int BOARD = 30;\nstatic const int TURNS = 300;\nstatic const int INF = 1e9;\n\nint N, M;\nvector<Pos> pets, humans;      // normalized coordinates after choosing corner\nvector<int> petType;\nbool wallg[31][31];            // 1..30 used\n\nint chosenCorner, Hrect, Wrect;\nint roleH = -1, roleV = -1, roleC = -1;\nvector<Pos> parkTarget;\nPos closerStandby;\n\nbool inside(int x, int y) {\n    return 1 <= x && x <= BOARD && 1 <= y && y <= BOARD;\n}\n\nPos addDir(Pos p, char d) {\n    if (d == 'U' || d == 'u') --p.x;\n    else if (d == 'D' || d == 'd') ++p.x;\n    else if (d == 'L' || d == 'l') --p.y;\n    else if (d == 'R' || d == 'r') ++p.y;\n    return p;\n}\n\n// corner transform:\n// 0: TL -> same\n// 1: TR -> mirror y\n// 2: BL -> mirror x\n// 3: BR -> mirror x,y\nPos transformPos(Pos p, int corner) {\n    if (corner == 0) return p;\n    if (corner == 1) return {p.x, BOARD + 1 - p.y};\n    if (corner == 2) return {BOARD + 1 - p.x, p.y};\n    return {BOARD + 1 - p.x, BOARD + 1 - p.y};\n}\n\n// same function works both ways because every transform is an involution\nchar mapDirByCorner(char c, int corner) {\n    bool lower = ('a' <= c && c <= 'z');\n    char d = (char)toupper(c);\n    if (corner == 1 || corner == 3) {\n        if (d == 'L') d = 'R';\n        else if (d == 'R') d = 'L';\n    }\n    if (corner == 2 || corner == 3) {\n        if (d == 'U') d = 'D';\n        else if (d == 'D') d = 'U';\n    }\n    if (lower) d = (char)tolower(d);\n    return d;\n}\n\nint manhattan(Pos a, Pos b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nbool canBuildCell(int tx, int ty, const vector<Pos>& hs, const vector<Pos>& ps) {\n    if (!inside(tx, ty)) return false;\n    if (wallg[tx][ty]) return false;\n    for (auto &h : hs) {\n        if (h.x == tx && h.y == ty) return false;\n    }\n    for (auto &p : ps) {\n        if (p.x == tx && p.y == ty) return false;\n        if (abs(p.x - tx) + abs(p.y - ty) == 1) return false;\n    }\n    return true;\n}\n\nchar bfsNextStep(Pos s, Pos t) {\n    if (s == t) return '.';\n    static int dist[31][31];\n    for (int i = 1; i <= BOARD; ++i) {\n        for (int j = 1; j <= BOARD; ++j) dist[i][j] = -1;\n    }\n    if (!inside(t.x, t.y) || wallg[t.x][t.y]) return '.';\n\n    queue<Pos> q;\n    dist[t.x][t.y] = 0;\n    q.push(t);\n\n    const char dirs[4] = {'U', 'D', 'L', 'R'};\n    while (!q.empty()) {\n        Pos cur = q.front(); q.pop();\n        for (char d : dirs) {\n            Pos nx = addDir(cur, d);\n            if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n            if (dist[nx.x][nx.y] != -1) continue;\n            dist[nx.x][nx.y] = dist[cur.x][cur.y] + 1;\n            q.push(nx);\n        }\n    }\n\n    int bestd = INF;\n    char best = '.';\n    // tie-breaking order can matter slightly; prefer moving toward upper-left inside region\n    const char order[4] = {'U', 'L', 'R', 'D'};\n    for (char d : order) {\n        Pos nx = addDir(s, d);\n        if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n        if (dist[nx.x][nx.y] == -1) continue;\n        if (dist[nx.x][nx.y] < bestd) {\n            bestd = dist[nx.x][nx.y];\n            best = d;\n        }\n    }\n    return best;\n}\n\nint countPetsInside() {\n    int c = 0;\n    for (auto &p : pets) if (p.x <= Hrect && p.y <= Wrect) ++c;\n    return c;\n}\n\nbool allHumansInside() {\n    for (auto &h : humans) {\n        if (h.x > Hrect || h.y > Wrect) return false;\n    }\n    return true;\n}\n\nbool nonDoorWallsBuilt() {\n    for (int y = 1; y <= Wrect - 1; ++y) {\n        if (!wallg[Hrect + 1][y]) return false;\n    }\n    for (int x = 1; x <= Hrect - 1; ++x) {\n        if (!wallg[x][Wrect + 1]) return false;\n    }\n    return true;\n}\n\nbool closedFully() {\n    return wallg[Hrect + 1][Wrect] && wallg[Hrect][Wrect + 1];\n}\n\nvector<Pos> transformedVec(const vector<Pos>& src, int corner) {\n    vector<Pos> res = src;\n    for (auto &p : res) p = transformPos(p, corner);\n    return res;\n}\n\nvoid chooseStrategy(const vector<Pos>& initPetsActual, const vector<Pos>& initHumansActual) {\n    double bestScore = -1e100;\n    int bestCorner = 0, bestH = 8, bestW = 8;\n\n    double pw[25];\n    pw[0] = 1.0;\n    for (int i = 1; i < 25; ++i) pw[i] = pw[i - 1] * 0.57;\n\n    for (int corner = 0; corner < 4; ++corner) {\n        auto tp = transformedVec(initPetsActual, corner);\n        auto th = transformedVec(initHumansActual, corner);\n\n        int occ[31][31] = {};\n        for (auto &p : tp) occ[p.x][p.y]++;\n\n        int pref[31][31] = {};\n        for (int i = 1; i <= BOARD; ++i) {\n            for (int j = 1; j <= BOARD; ++j) {\n                pref[i][j] = occ[i][j] + pref[i-1][j] + pref[i][j-1] - pref[i-1][j-1];\n            }\n        }\n\n        for (int H = 6; H <= 16; ++H) {\n            for (int W = 6; W <= 16; ++W) {\n                int petCnt = pref[H][W];\n\n                int bestRoleCost = INF;\n                for (int a = 0; a < M; ++a) {\n                    int da = manhattan(th[a], {H, 1});\n                    for (int b = 0; b < M; ++b) if (b != a) {\n                        int dab = da + manhattan(th[b], {1, W});\n                        for (int c = 0; c < M; ++c) if (c != a && c != b) {\n                            int cost = dab + manhattan(th[c], {H, W});\n                            bestRoleCost = min(bestRoleCost, cost);\n                        }\n                    }\n                }\n\n                double area = 1.0 * H * W;\n                double score = area * pw[min(petCnt, 24)] - 0.8 * (H + W) - 0.25 * bestRoleCost;\n                if (petCnt == 0) score += 8.0;\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestCorner = corner;\n                    bestH = H;\n                    bestW = W;\n                }\n            }\n        }\n    }\n\n    chosenCorner = bestCorner;\n    Hrect = bestH;\n    Wrect = bestW;\n\n    pets = transformedVec(initPetsActual, chosenCorner);\n    humans = transformedVec(initHumansActual, chosenCorner);\n\n    // choose roles\n    int bestCost = INF;\n    for (int a = 0; a < M; ++a) {\n        int da = manhattan(humans[a], {Hrect, 1});\n        for (int b = 0; b < M; ++b) if (b != a) {\n            int dab = da + manhattan(humans[b], {1, Wrect});\n            for (int c = 0; c < M; ++c) if (c != a && c != b) {\n                int cost = dab + manhattan(humans[c], {Hrect, Wrect});\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    roleH = a;\n                    roleV = b;\n                    roleC = c;\n                }\n            }\n        }\n    }\n\n    closerStandby = {max(1, Hrect - 1), max(1, Wrect - 1)};\n    if (closerStandby.x == Hrect && closerStandby.y == Wrect) closerStandby = {1, 1};\n\n    parkTarget.assign(M, {1, 1});\n    parkTarget[roleH] = {Hrect, 1};\n    parkTarget[roleV] = {1, Wrect};\n    parkTarget[roleC] = closerStandby;\n\n    vector<Pos> spots;\n    for (int sum = 2; sum <= Hrect + Wrect; ++sum) {\n        for (int x = 1; x <= Hrect; ++x) {\n            int y = sum - x;\n            if (1 <= y && y <= Wrect) {\n                Pos p{x, y};\n                if (p == Pos{Hrect, 1}) continue;\n                if (p == Pos{1, Wrect}) continue;\n                if (p == Pos{Hrect, Wrect}) continue;\n                if (p == closerStandby) continue;\n                spots.push_back(p);\n            }\n        }\n    }\n\n    int ptr = 0;\n    for (int i = 0; i < M; ++i) {\n        if (i == roleH || i == roleV || i == roleC) continue;\n        if (ptr < (int)spots.size()) parkTarget[i] = spots[ptr++];\n        else parkTarget[i] = {1, 1};\n    }\n\n    memset(wallg, 0, sizeof(wallg));\n}\n\nchar decideHorizontalBuilder(int id, const vector<Pos>& hs, const vector<Pos>& ps) {\n    Pos cur = hs[id];\n\n    vector<int> rem;\n    for (int y = 1; y <= Wrect - 1; ++y) {\n        if (!wallg[Hrect + 1][y]) rem.push_back(y);\n    }\n    if (rem.empty()) return bfsNextStep(cur, parkTarget[id]);\n\n    if (cur.x == Hrect && 1 <= cur.y && cur.y <= Wrect - 1 && !wallg[Hrect + 1][cur.y]) {\n        if (canBuildCell(Hrect + 1, cur.y, hs, ps)) return 'd';\n    }\n\n    int bestY = -1;\n    int bestD = INF;\n    for (int y : rem) {\n        int d = abs(cur.x - Hrect) + abs(cur.y - y);\n        if (cur.x == Hrect && cur.y == y && !canBuildCell(Hrect + 1, y, hs, ps) && (int)rem.size() >= 2) {\n            d += 1000;\n        }\n        if (d < bestD) {\n            bestD = d;\n            bestY = y;\n        }\n    }\n    if (bestY == -1) return '.';\n    return bfsNextStep(cur, {Hrect, bestY});\n}\n\nchar decideVerticalBuilder(int id, const vector<Pos>& hs, const vector<Pos>& ps) {\n    Pos cur = hs[id];\n\n    vector<int> rem;\n    for (int x = 1; x <= Hrect - 1; ++x) {\n        if (!wallg[x][Wrect + 1]) rem.push_back(x);\n    }\n    if (rem.empty()) return bfsNextStep(cur, parkTarget[id]);\n\n    if (cur.y == Wrect && 1 <= cur.x && cur.x <= Hrect - 1 && !wallg[cur.x][Wrect + 1]) {\n        if (canBuildCell(cur.x, Wrect + 1, hs, ps)) return 'r';\n    }\n\n    int bestX = -1;\n    int bestD = INF;\n    for (int x : rem) {\n        int d = abs(cur.x - x) + abs(cur.y - Wrect);\n        if (cur.x == x && cur.y == Wrect && !canBuildCell(x, Wrect + 1, hs, ps) && (int)rem.size() >= 2) {\n            d += 1000;\n        }\n        if (d < bestD) {\n            bestD = d;\n            bestX = x;\n        }\n    }\n    if (bestX == -1) return '.';\n    return bfsNextStep(cur, {bestX, Wrect});\n}\n\nchar decideCloser(int turn, int id, const vector<Pos>& hs, const vector<Pos>& ps) {\n    Pos cur = hs[id];\n\n    bool nonDoor = nonDoorWallsBuilt();\n    bool allIn = allHumansInside();\n    bool door1 = wallg[Hrect + 1][Wrect];\n    bool door2 = wallg[Hrect][Wrect + 1];\n    bool started = door1 || door2;\n    bool closed = door1 && door2;\n    int pin = countPetsInside();\n\n    bool closeNow = false;\n    if (!closed && allIn && nonDoor) {\n        if (started) closeNow = true;\n        else if (pin == 0) closeNow = true;\n        else if (turn >= 250 && pin <= 1) closeNow = true;\n        else if (turn >= 290 && pin <= 2) closeNow = true;\n        else if (turn >= 297) closeNow = true;\n    }\n\n    if (!closeNow && !started) {\n        return bfsNextStep(cur, closerStandby);\n    }\n\n    if (cur != Pos{Hrect, Wrect}) {\n        return bfsNextStep(cur, {Hrect, Wrect});\n    }\n\n    if (!door1 && canBuildCell(Hrect + 1, Wrect, hs, ps)) return 'd';\n    if (!door2 && canBuildCell(Hrect, Wrect + 1, hs, ps)) return 'r';\n    return '.';\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<Pos> initPetsActual(N);\n    petType.resize(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> initPetsActual[i].x >> initPetsActual[i].y >> petType[i];\n    }\n    cin >> M;\n    vector<Pos> initHumansActual(M);\n    for (int i = 0; i < M; ++i) {\n        cin >> initHumansActual[i].x >> initHumansActual[i].y;\n    }\n\n    chooseStrategy(initPetsActual, initHumansActual);\n\n    for (int turn = 0; turn < TURNS; ++turn) {\n        vector<Pos> hs0 = humans;\n        vector<Pos> ps0 = pets;\n\n        vector<char> act(M, '.');\n\n        for (int i = 0; i < M; ++i) {\n            if (i == roleH) act[i] = decideHorizontalBuilder(i, hs0, ps0);\n            else if (i == roleV) act[i] = decideVerticalBuilder(i, hs0, ps0);\n            else if (i == roleC) act[i] = decideCloser(turn, i, hs0, ps0);\n            else act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n        }\n\n        // sanitize build actions and detect duplicate build targets\n        set<pair<int,int>> buildSet;\n        vector<Pos> buildTarget(M, {-1, -1});\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!canBuildCell(t.x, t.y, hs0, ps0)) {\n                    act[i] = '.';\n                    continue;\n                }\n                if (buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                    continue;\n                }\n                buildSet.insert({t.x, t.y});\n                buildTarget[i] = t;\n            }\n        }\n\n        // sanitize move actions\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!inside(t.x, t.y) || wallg[t.x][t.y] || buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        string out(M, '.');\n        for (int i = 0; i < M; ++i) out[i] = mapDirByCorner(act[i], chosenCorner);\n        cout << out << '\\n';\n        cout.flush();\n\n        // update internal state after humans act\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (canBuildCell(t.x, t.y, hs0, ps0)) wallg[t.x][t.y] = true;\n            }\n        }\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (inside(t.x, t.y) && !wallg[t.x][t.y] && !buildSet.count({t.x, t.y})) {\n                    humans[i] = t;\n                }\n            }\n        }\n\n        // read pet moves\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                if (c == '.') continue;\n                char nc = mapDirByCorner(c, chosenCorner);\n                pets[i] = addDir(pets[i], nc);\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 = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr char DIRS[4] = {'U', 'D', 'L', 'R'};\n\nstruct State {\n    array<float, V> pr{};\n    array<char, MAXL> path{};\n    double score = 0.0;   // exact accumulated expected score so far\n    double upper = 0.0;   // safe optimistic upper bound\n    double pri = 0.0;     // heuristic priority\n    int len = 0;\n};\n\nint si, sj, ti, tj;\ndouble P, Q;\nstring h[N];\nstring vwall[N - 1];\n\nint target_id, start_id;\nint nxtPos[V][4];\nint distToTarget[V];\n\ndouble ubVal[MAXL + 1][V];   // safe upper-bound contribution after step s\ndouble heVal[MAXL + 1][V];   // heuristic contribution after step s\n\ninline int id(int i, int j) { return i * N + j; }\ninline int row_of(int x) { return x / N; }\ninline int col_of(int x) { return x % N; }\n\nint dirIndex(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\n\nstring toString(const State& st) {\n    return string(st.path.begin(), st.path.begin() + st.len);\n}\n\nvoid buildTransitions() {\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int x = id(i, j);\n\n            // U\n            if (i == 0 || vwall[i - 1][j] == '1') nxtPos[x][0] = x;\n            else nxtPos[x][0] = id(i - 1, j);\n\n            // D\n            if (i == N - 1 || vwall[i][j] == '1') nxtPos[x][1] = x;\n            else nxtPos[x][1] = id(i + 1, j);\n\n            // L\n            if (j == 0 || h[i][j - 1] == '1') nxtPos[x][2] = x;\n            else nxtPos[x][2] = id(i, j - 1);\n\n            // R\n            if (j == N - 1 || h[i][j] == '1') nxtPos[x][3] = x;\n            else nxtPos[x][3] = id(i, j + 1);\n        }\n    }\n}\n\nvoid bfsDistances() {\n    fill(distToTarget, distToTarget + V, (int)1e9);\n    queue<int> q;\n    distToTarget[target_id] = 0;\n    q.push(target_id);\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        int d = distToTarget[x];\n        int i = row_of(x), j = col_of(x);\n\n        // Traverse actual graph neighbors\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (distToTarget[y] > d + 1) {\n                distToTarget[y] = d + 1;\n                q.push(y);\n            }\n        }\n    }\n}\n\nvoid buildHeuristics() {\n    for (int step = 0; step <= MAXL; step++) {\n        int rem = MAXL - step;\n        for (int x = 0; x < V; x++) {\n            int d = distToTarget[x];\n            if (d <= rem) {\n                ubVal[step][x] = max(0.0, 401.0 - step - d);\n                heVal[step][x] = max(0.0, 401.0 - step - d / Q);\n            } else {\n                ubVal[step][x] = 0.0;\n                heVal[step][x] = 0.0;\n            }\n        }\n    }\n}\n\nState initialState() {\n    State st;\n    st.pr.fill(0.0f);\n    st.pr[start_id] = 1.0f;\n    st.score = 0.0;\n    st.len = 0;\n\n    double ub = ubVal[0][start_id];\n    double he = heVal[0][start_id];\n    st.upper = ub;\n    st.pri = he;\n    return st;\n}\n\nState extendState(const State& st, int a, int step) {\n    State nx;\n    nx.pr.fill(0.0f);\n    nx.path = st.path;\n    nx.path[st.len] = DIRS[a];\n    nx.len = st.len + 1;\n    nx.score = st.score;\n\n    double ub = 0.0;\n    double he = 0.0;\n    const double hitReward = 401.0 - step;\n\n    for (int x = 0; x < V; x++) {\n        float q = st.pr[x];\n        if (q < 1e-8f) continue;\n\n        int y = nxtPos[x][a];\n\n        if (y == target_id) {\n            float stay = q * (float)P;\n            if (stay > 0) {\n                nx.pr[x] += stay;\n                ub += (double)stay * ubVal[step][x];\n                he += (double)stay * heVal[step][x];\n            }\n            nx.score += (double)q * Q * hitReward;\n        } else if (y == x) {\n            nx.pr[x] += q;\n            ub += (double)q * ubVal[step][x];\n            he += (double)q * heVal[step][x];\n        } else {\n            float stay = q * (float)P;\n            float go = q * (float)Q;\n            if (stay > 0) {\n                nx.pr[x] += stay;\n                ub += (double)stay * ubVal[step][x];\n                he += (double)stay * heVal[step][x];\n            }\n            if (go > 0) {\n                nx.pr[y] += go;\n                ub += (double)go * ubVal[step][y];\n                he += (double)go * heVal[step][y];\n            }\n        }\n    }\n\n    nx.upper = nx.score + ub;\n    nx.pri = nx.score + he;\n    return nx;\n}\n\ndouble evaluateString(const string& s) {\n    array<double, V> cur{}, nxt{};\n    cur.fill(0.0);\n    cur[start_id] = 1.0;\n    double score = 0.0;\n\n    for (int step = 1; step <= (int)s.size(); step++) {\n        nxt.fill(0.0);\n        int a = dirIndex(s[step - 1]);\n        double hitReward = 401.0 - step;\n\n        for (int x = 0; x < V; x++) {\n            double q = cur[x];\n            if (q < 1e-14) continue;\n\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                nxt[x] += q * P;\n                score += q * Q * hitReward;\n            } else if (y == x) {\n                nxt[x] += q;\n            } else {\n                nxt[x] += q * P;\n                nxt[y] += q * Q;\n            }\n        }\n        cur.swap(nxt);\n    }\n    return score;\n}\n\nState applyPrefix(const string& s) {\n    State st = initialState();\n    for (int step = 1; step <= (int)s.size(); step++) {\n        st = extendState(st, dirIndex(s[step - 1]), step);\n    }\n    return st;\n}\n\nState greedyComplete(State cur, bool useUpperMetric) {\n    for (int step = cur.len + 1; step <= MAXL; step++) {\n        State best;\n        bool first = true;\n        for (int a = 0; a < 4; a++) {\n            State nx = extendState(cur, a, step);\n            double key = useUpperMetric ? nx.upper : nx.pri;\n            if (first) {\n                best = std::move(nx);\n                first = false;\n            } else {\n                double bestKey = useUpperMetric ? best.upper : best.pri;\n                if (key > bestKey + 1e-12 ||\n                    (abs(key - bestKey) <= 1e-12 && nx.score > best.score)) {\n                    best = std::move(nx);\n                }\n            }\n        }\n        cur = std::move(best);\n    }\n    return cur;\n}\n\nstring shortestPathString() {\n    vector<int> prev(V, -1), prevDir(V, -1);\n    queue<int> q;\n    q.push(start_id);\n    prev[start_id] = start_id;\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        if (x == target_id) break;\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (prev[y] == -1) {\n                prev[y] = x;\n                prevDir[y] = a;\n                q.push(y);\n            }\n        }\n    }\n\n    if (prev[target_id] == -1) return \"\";\n\n    string res;\n    int cur = target_id;\n    while (cur != start_id) {\n        res.push_back(DIRS[prevDir[cur]]);\n        cur = prev[cur];\n    }\n    reverse(res.begin(), res.end());\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> P;\n    Q = 1.0 - P;\n    for (int i = 0; i < N; i++) cin >> h[i];\n    for (int i = 0; i < N - 1; i++) cin >> vwall[i];\n\n    start_id = id(si, sj);\n    target_id = id(ti, tj);\n\n    auto timeStart = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - timeStart).count();\n    };\n\n    buildTransitions();\n    bfsDistances();\n    buildHeuristics();\n\n    double bestScore = -1.0;\n    string bestAnswer;\n\n    auto relaxBest = [&](const State& st) {\n        if (st.len == MAXL) {\n            if (st.score > bestScore + 1e-12) {\n                bestScore = st.score;\n                bestAnswer = toString(st);\n            }\n        }\n    };\n    auto relaxBestStr = [&](const string& s, double sc) {\n        if ((int)s.size() == MAXL && sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAnswer = s;\n        }\n    };\n\n    // Initial greedy lower bounds\n    {\n        State init = initialState();\n\n        State g1 = greedyComplete(init, false);\n        relaxBest(g1);\n\n        State g2 = greedyComplete(init, true);\n        relaxBest(g2);\n\n        for (int a = 0; a < 4; a++) {\n            State first = extendState(init, a, 1);\n            State g = greedyComplete(first, false);\n            relaxBest(g);\n        }\n\n        string sp = shortestPathString();\n        if (!sp.empty() && (int)sp.size() <= MAXL) {\n            State pref = applyPrefix(sp);\n            State g = greedyComplete(pref, false);\n            relaxBest(g);\n        }\n    }\n\n    // Beam search over prefixes\n    const int BEAM_WIDTH = 200;\n    vector<State> beam, cand;\n    beam.reserve(BEAM_WIDTH);\n    cand.reserve(BEAM_WIDTH * 4 + 10);\n\n    beam.push_back(initialState());\n\n    auto cmpState = [](const State& a, const State& b) {\n        if (fabs(a.pri - b.pri) > 1e-12) return a.pri > b.pri;\n        if (fabs(a.upper - b.upper) > 1e-12) return a.upper > b.upper;\n        return a.score > b.score;\n    };\n\n    for (int step = 1; step <= MAXL; step++) {\n        cand.clear();\n\n        for (const State& st : beam) {\n            for (int a = 0; a < 4; a++) {\n                State nx = extendState(st, a, step);\n                if (nx.upper + 1e-12 < bestScore) continue; // safe pruning\n                cand.push_back(std::move(nx));\n            }\n        }\n\n        if (cand.empty()) break;\n\n        if ((int)cand.size() > BEAM_WIDTH) {\n            nth_element(cand.begin(), cand.begin() + BEAM_WIDTH, cand.end(), cmpState);\n            cand.resize(BEAM_WIDTH);\n        }\n        sort(cand.begin(), cand.end(), cmpState);\n        beam.swap(cand);\n\n        // Periodically greedily complete the best current prefix to tighten lower bound\n        if (!beam.empty() && (step <= 30 || step % 2 == 0)) {\n            State g = greedyComplete(beam[0], false);\n            relaxBest(g);\n        }\n\n        if (elapsed() > 1.55) break;\n    }\n\n    // If beam reached full length, inspect all survivors\n    for (const State& st : beam) {\n        if (st.len == MAXL) relaxBest(st);\n    }\n\n    // Fallback, should not happen\n    if (bestAnswer.empty()) {\n        State g = greedyComplete(initialState(), false);\n        bestAnswer = toString(g);\n        bestScore = g.score;\n    }\n\n    // Lightweight hill climbing: single-character replacement\n    if (elapsed() < 1.90) {\n        string cur = bestAnswer;\n        double curScore = bestScore;\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool improved = false;\n            for (int i = 0; i < MAXL; i++) {\n                if (elapsed() > 1.95) break;\n                char orig = cur[i];\n                char bestC = orig;\n                double localBest = curScore;\n\n                for (char c : DIRS) {\n                    if (c == orig) continue;\n                    cur[i] = c;\n                    double sc = evaluateString(cur);\n                    if (sc > localBest + 1e-12) {\n                        localBest = sc;\n                        bestC = c;\n                    }\n                }\n                cur[i] = bestC;\n                if (localBest > curScore + 1e-12) {\n                    curScore = localBest;\n                    improved = true;\n                } else {\n                    cur[i] = orig;\n                }\n            }\n            if (!improved) break;\n        }\n\n        if (curScore > bestScore + 1e-12) {\n            bestScore = curScore;\n            bestAnswer = cur;\n        }\n    }\n\n    cout << bestAnswer << '\\n';\n    return 0;\n}","ahc010":"#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    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int CELLS = N * N;\nstatic constexpr int SIDES = CELLS * 4;\n\nstatic constexpr int di[4] = {0, -1, 0, 1};\nstatic constexpr int dj[4] = {-1, 0, 1, 0};\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\n// rotation by 90 degrees counterclockwise\nstatic constexpr int ROT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\n\n// partner[ state ][ entering-side ] = leaving-side, -1 if unused\nstatic constexpr int PARTNER[8][4] = {\n    {1, 0, -1, -1},   // 0\n    {3, -1, -1, 0},   // 1\n    {-1, -1, 3, 2},   // 2\n    {-1, 2, 1, -1},   // 3\n    {1, 0, 3, 2},     // 4\n    {3, 2, 1, 0},     // 5\n    {2, -1, 0, -1},   // 6\n    {-1, 3, -1, 1},   // 7\n};\n\nstruct Eval {\n    long long score = 0;   // official score = top1 * top2 (or 0)\n    long long aux = 0;     // search objective\n    long long sumsq = 0;\n    int top1 = 0, top2 = 0;\n    int loops = 0;\n    int conn = 0;          // local connectivity score\n};\n\nstruct CandidateState {\n    array<uint8_t, CELLS> st{};\n    Eval ev;\n};\n\nstruct Solver {\n    array<string, N> input{};\n    array<uint8_t, CELLS> orig{};\n    uint8_t cand[CELLS][4]{};\n    uint8_t candCnt[CELLS]{};\n    int rotTo[8][8];\n    int mask[8];\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n    const double TIME_LIMIT = 1.95;\n\n    Solver() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng = XorShift64(seed);\n\n        memset(rotTo, -1, sizeof(rotTo));\n        for (int t = 0; t < 8; t++) {\n            int cur = t;\n            for (int k = 0; k < 4; k++) {\n                if (rotTo[t][cur] == -1) rotTo[t][cur] = k;\n                cur = ROT[cur];\n            }\n        }\n\n        for (int s = 0; s < 8; s++) {\n            int m = 0;\n            for (int d = 0; d < 4; d++) if (PARTNER[s][d] != -1) m |= (1 << d);\n            mask[s] = m;\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void read_input() {\n        for (int i = 0; i < N; i++) cin >> input[i];\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                orig[idx] = (uint8_t)(input[i][j] - '0');\n                int t = orig[idx];\n                if (0 <= t && t <= 3) {\n                    candCnt[idx] = 4;\n                    cand[idx][0] = 0;\n                    cand[idx][1] = 1;\n                    cand[idx][2] = 2;\n                    cand[idx][3] = 3;\n                } else if (t == 4 || t == 5) {\n                    candCnt[idx] = 2;\n                    cand[idx][0] = 4;\n                    cand[idx][1] = 5;\n                } else {\n                    candCnt[idx] = 2;\n                    cand[idx][0] = 6;\n                    cand[idx][1] = 7;\n                }\n            }\n        }\n    }\n\n    inline void addEdge(int u, int v, int deg[], int adj[][2]) const {\n        adj[u][deg[u]++] = v;\n        adj[v][deg[v]++] = u;\n    }\n\n    Eval evaluate(const array<uint8_t, CELLS>& st) const {\n        static int deg[SIDES];\n        static int adj[SIDES][2];\n        static uint8_t vis[SIDES];\n\n        for (int x = 0; x < SIDES; x++) {\n            deg[x] = -1;\n            vis[x] = 0;\n        }\n\n        Eval res;\n\n        // initialize used side nodes + tile internal edges + boundary penalties\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                int s = st[c];\n                int m = mask[s];\n\n                for (int d = 0; d < 4; d++) {\n                    int id = c * 4 + d;\n                    if (m & (1 << d)) deg[id] = 0;\n                }\n\n                for (int d = 0; d < 4; d++) {\n                    int p = PARTNER[s][d];\n                    if (p != -1 && d < p) {\n                        addEdge(c * 4 + d, c * 4 + p, deg, adj);\n                    }\n                }\n\n                if (j == 0     && (m & (1 << 0))) res.conn -= 3;\n                if (i == 0     && (m & (1 << 1))) res.conn -= 3;\n                if (j == N - 1 && (m & (1 << 2))) res.conn -= 3;\n                if (i == N - 1 && (m & (1 << 3))) res.conn -= 3;\n            }\n        }\n\n        // neighbor edges + local connectivity score\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j + 1 < N; j++) {\n                int a = i * N + j;\n                int b = i * N + (j + 1);\n                bool ua = (mask[st[a]] >> 2) & 1; // right\n                bool ub = (mask[st[b]] >> 0) & 1; // left\n                if (ua && ub) {\n                    addEdge(a * 4 + 2, b * 4 + 0, deg, adj);\n                    res.conn += 2;\n                } else if (ua ^ ub) {\n                    res.conn -= 3;\n                }\n            }\n        }\n        for (int i = 0; i + 1 < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int a = i * N + j;\n                int b = (i + 1) * N + j;\n                bool ua = (mask[st[a]] >> 3) & 1; // down\n                bool ub = (mask[st[b]] >> 1) & 1; // up\n                if (ua && ub) {\n                    addEdge(a * 4 + 3, b * 4 + 1, deg, adj);\n                    res.conn += 2;\n                } else if (ua ^ ub) {\n                    res.conn -= 3;\n                }\n            }\n        }\n\n        // find cycle components\n        static int q[SIDES];\n        for (int v = 0; v < SIDES; v++) {\n            if (deg[v] == -1 || vis[v]) continue;\n            int head = 0, tail = 0;\n            q[tail++] = v;\n            vis[v] = 1;\n\n            int cnt = 0;\n            bool all2 = true;\n\n            while (head < tail) {\n                int u = q[head++];\n                cnt++;\n                if (deg[u] != 2) all2 = false;\n                for (int k = 0; k < deg[u]; k++) {\n                    int to = adj[u][k];\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[tail++] = to;\n                    }\n                }\n            }\n\n            if (all2) {\n                int len = cnt / 2;\n                res.loops++;\n                res.sumsq += 1LL * len * len;\n                if (len > res.top1) {\n                    res.top2 = res.top1;\n                    res.top1 = len;\n                } else if (len > res.top2) {\n                    res.top2 = len;\n                }\n            }\n        }\n\n        if (res.loops >= 2) res.score = 1LL * res.top1 * res.top2;\n        else res.score = 0;\n\n        // official score first, then sumsq, then local consistency\n        res.aux = res.score * 1000000LL + res.sumsq * 100LL + res.conn;\n        return res;\n    }\n\n    inline bool betterFinal(const Eval& a, const Eval& b) const {\n        if (a.score != b.score) return a.score > b.score;\n        return a.aux > b.aux;\n    }\n\n    inline bool betterAux(const Eval& a, const Eval& b) const {\n        return a.aux > b.aux;\n    }\n\n    int localCellScore(const array<uint8_t, CELLS>& st, int pos, int ns) const {\n        int i = pos / N;\n        int j = pos % N;\n        int m = mask[ns];\n        int sc = 0;\n        for (int d = 0; d < 4; d++) {\n            bool used = (m >> d) & 1;\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (used) sc -= 3;\n            } else {\n                int np = ni * N + nj;\n                bool nused = (mask[st[np]] >> opp[d]) & 1;\n                if (used && nused) sc += 2;\n                else if (used ^ nused) sc -= 3;\n            }\n        }\n        return sc;\n    }\n\n    void localImprove(array<uint8_t, CELLS>& st, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                int pos = order[ii];\n                int cur = st[pos];\n                int bestState = cur;\n                int bestScore = localCellScore(st, pos, cur);\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    int ns = cand[pos][k];\n                    if (ns == cur) continue;\n                    int sc = localCellScore(st, pos, ns);\n                    if (sc > bestScore || (sc == bestScore && rng.next_int(2) == 0)) {\n                        bestScore = sc;\n                        bestState = ns;\n                    }\n                }\n                if (bestState != cur) {\n                    st[pos] = (uint8_t)bestState;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void exactDescent(array<uint8_t, CELLS>& st, Eval& cur, int maxSweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < maxSweeps; sw++) {\n            if (elapsed() > TIME_LIMIT) return;\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                if (elapsed() > TIME_LIMIT) return;\n                int pos = order[ii];\n\n                uint8_t origState = st[pos];\n                uint8_t bestState = origState;\n                Eval bestEval = cur;\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == origState) continue;\n                    st[pos] = ns;\n                    Eval ev = evaluate(st);\n                    if (betterAux(ev, bestEval)) {\n                        bestEval = ev;\n                        bestState = ns;\n                    }\n                }\n\n                st[pos] = bestState;\n                if (bestState != origState) {\n                    cur = bestEval;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void addSeed(vector<CandidateState>& seeds, const CandidateState& c) const {\n        seeds.push_back(c);\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n        if ((int)seeds.size() > 4) seeds.resize(4);\n    }\n\n    string solve() {\n        start_time = chrono::steady_clock::now();\n\n        vector<CandidateState> seeds;\n\n        // seed 0: original orientation\n        {\n            CandidateState c;\n            c.st = orig;\n            localImprove(c.st, 6);\n            c.ev = evaluate(c.st);\n            addSeed(seeds, c);\n        }\n\n        // random seeds\n        while (elapsed() < 0.35) {\n            CandidateState c;\n            for (int p = 0; p < CELLS; p++) {\n                c.st[p] = cand[p][rng.next_int(candCnt[p])];\n            }\n            localImprove(c.st, 8);\n            c.ev = evaluate(c.st);\n            addSeed(seeds, c);\n        }\n\n        // refine top seeds\n        for (int i = 0; i < (int)seeds.size(); i++) {\n            if (elapsed() > 0.90) break;\n            exactDescent(seeds[i].st, seeds[i].ev, 2);\n        }\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n\n        // iterative perturb + repair\n        while (elapsed() < TIME_LIMIT) {\n            int baseId = rng.next_int((int)seeds.size());\n            CandidateState cur = seeds[baseId];\n\n            int k = 4 + rng.next_int(18);\n            for (int t = 0; t < k; t++) {\n                int pos = rng.next_int(CELLS);\n                if (candCnt[pos] == 1) continue;\n                uint8_t now = cur.st[pos];\n                uint8_t ns = now;\n                for (int tries = 0; tries < 5 && ns == now; tries++) {\n                    ns = cand[pos][rng.next_int(candCnt[pos])];\n                }\n                cur.st[pos] = ns;\n            }\n\n            localImprove(cur.st, 2);\n            cur.ev = evaluate(cur.st);\n            exactDescent(cur.st, cur.ev, 1);\n\n            if (betterFinal(cur.ev, seeds[0].ev)) {\n                addSeed(seeds, cur);\n            } else {\n                // even if not best, keep some diversity\n                addSeed(seeds, cur);\n            }\n        }\n\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n        const auto& best = seeds[0].st;\n\n        string ans;\n        ans.reserve(CELLS);\n        for (int p = 0; p < CELLS; p++) {\n            int t = orig[p];\n            int s = best[p];\n            int r = rotTo[t][s];\n            if (r < 0) r = 0; // should not happen\n            ans.push_back(char('0' + r));\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXM = 100;\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 DSU {\n    int p[MAXM], sz[MAXM];\n    void init(int n) {\n        for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1;\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\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\nstruct Metrics {\n    int largestTree = 0;\n    int largestCC = 0;\n    int cycleExcess = 0;\n    int stubs = 0;\n    int matchedEdges = 0;\n};\n\nstruct State {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;   // move used from parent to this state\n    Metrics mt;\n};\n\nstruct Cand {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    Metrics mt;\n};\n\nstruct BestRef {\n    bool isTemp = false; // false: nodeIdx valid, true: parent+lastMove valid\n    int nodeIdx = 0;\n    int parent = -1;\n    char lastMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nuint64_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 hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nchar opposite(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    if (c == 'R') return 'L';\n    return 0;\n}\n\nbool betterMetric(const Metrics& a, const Metrics& b) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.stubs != b.stubs) return a.stubs < b.stubs;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    return false;\n}\n\nbool betterBest(const Metrics& a, int depthA, const Metrics& b, int depthB, int fullSize) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestTree == fullSize && depthA != depthB) return depthA < depthB;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.stubs != b.stubs) return a.stubs < b.stubs;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    return false;\n}\n\nMetrics evaluateBoard(const array<uint8_t, MAXM>& board, int N) {\n    int M = N * N;\n    static int pop4[16] = {\n        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4\n    };\n\n    DSU dsu;\n    dsu.init(M);\n\n    int degreeSum = 0;\n    int eu[2 * MAXM], ev[2 * MAXM];\n    int ecount = 0;\n\n    for (int i = 0; i < M; i++) {\n        degreeSum += pop4[board[i]];\n    }\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            uint8_t t = board[id];\n            if (t == 0) continue;\n\n            if (c + 1 < N) {\n                int id2 = id + 1;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 4) && (u & 1)) {\n                    dsu.unite(id, id2);\n                    eu[ecount] = id;\n                    ev[ecount] = id2;\n                    ecount++;\n                }\n            }\n            if (r + 1 < N) {\n                int id2 = id + N;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 8) && (u & 2)) {\n                    dsu.unite(id, id2);\n                    eu[ecount] = id;\n                    ev[ecount] = id2;\n                    ecount++;\n                }\n            }\n        }\n    }\n\n    int vertices[MAXM] = {};\n    int edges[MAXM] = {};\n\n    for (int i = 0; i < M; i++) {\n        if (board[i] == 0) continue;\n        vertices[dsu.find(i)]++;\n    }\n    for (int k = 0; k < ecount; k++) {\n        edges[dsu.find(eu[k])]++;\n    }\n\n    Metrics mt;\n    mt.matchedEdges = ecount;\n    mt.stubs = degreeSum - 2 * ecount;\n\n    for (int i = 0; i < M; i++) {\n        if (vertices[i] == 0) continue;\n        int v = vertices[i];\n        int e = edges[i];\n        mt.largestCC = max(mt.largestCC, v);\n        if (e == v - 1) mt.largestTree = max(mt.largestTree, v);\n        mt.cycleExcess += max(0, e - v + 1);\n    }\n\n    return mt;\n}\n\nstring reconstructPathFromNode(const vector<State>& nodes, int idx) {\n    string s;\n    while (idx > 0) {\n        s.push_back(nodes[idx].prevMove);\n        idx = nodes[idx].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    cin >> N >> T;\n    int M = N * N;\n    int FULL = M - 1;\n\n    array<uint8_t, MAXM> initBoard{};\n    int initEmpty = -1;\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            initBoard[i * N + j] = (uint8_t)v;\n            if (v == 0) initEmpty = i * N + j;\n        }\n    }\n\n    uint64_t zob[MAXM][16];\n    uint64_t seed = 12345678901234567ULL;\n    for (int i = 0; i < MAXM; i++) {\n        for (int j = 0; j < 16; j++) {\n            seed = splitmix64(seed);\n            zob[i][j] = seed;\n        }\n    }\n\n    uint64_t initHash = 0;\n    for (int i = 0; i < M; i++) initHash ^= zob[i][initBoard[i]];\n\n    State root;\n    root.board = initBoard;\n    root.hash = initHash;\n    root.empty = initEmpty;\n    root.parent = -1;\n    root.prevMove = 0;\n    root.mt = evaluateBoard(root.board, N);\n\n    if (root.mt.largestTree == FULL) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    int beamWidth;\n    if (N <= 7) beamWidth = 220;\n    else if (N == 8) beamWidth = 180;\n    else if (N == 9) beamWidth = 140;\n    else beamWidth = 110;\n\n    vector<State> nodes;\n    nodes.reserve(1 + beamWidth * (T + 1));\n    nodes.push_back(root);\n\n    BestRef best;\n    best.isTemp = false;\n    best.nodeIdx = 0;\n    best.depth = 0;\n    best.mt = root.mt;\n\n    vector<int> cur, nxt;\n    cur.push_back(0);\n\n    Timer timer;\n    const double TIME_LIMIT = 2.85;\n\n    const char moves[4] = {'U', 'D', 'L', 'R'};\n\n    for (int depth = 0; depth < T; depth++) {\n        if (timer.elapsed() > TIME_LIMIT) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 4);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 16);\n\n        bool foundFull = false;\n\n        for (int idx : cur) {\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                Cand cd;\n                cd.board = st.board;\n                uint8_t tile = cd.board[np];\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.hash = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                cd.mt = evaluateBoard(cd.board, N);\n\n                if (betterBest(cd.mt, depth + 1, best.mt, best.depth, FULL)) {\n                    best.isTemp = true;\n                    best.parent = idx;\n                    best.lastMove = mv;\n                    best.depth = depth + 1;\n                    best.mt = cd.mt;\n                }\n\n                if (cd.mt.largestTree == FULL) {\n                    foundFull = true;\n                    break;\n                }\n\n                auto it = seen.find(cd.hash);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(cd.hash, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (betterMetric(cd.mt, cands[pos].mt)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n            if (foundFull) break;\n        }\n\n        if (best.mt.largestTree == FULL) break;\n        if (cands.empty()) break;\n\n        auto cmpCand = [](const Cand& a, const Cand& b) {\n            return betterMetric(a.mt, b.mt);\n        };\n\n        if ((int)cands.size() > beamWidth) {\n            nth_element(cands.begin(), cands.begin() + beamWidth, cands.end(), cmpCand);\n            cands.resize(beamWidth);\n        }\n        sort(cands.begin(), cands.end(), cmpCand);\n\n        nxt.clear();\n        nxt.reserve(cands.size());\n\n        for (auto& cd : cands) {\n            State ns;\n            ns.board = cd.board;\n            ns.hash = cd.hash;\n            ns.empty = cd.empty;\n            ns.parent = cd.parent;\n            ns.prevMove = cd.prevMove;\n            ns.mt = cd.mt;\n            int nid = (int)nodes.size();\n            nodes.push_back(std::move(ns));\n            nxt.push_back(nid);\n\n            if (betterBest(nodes[nid].mt, depth + 1, best.mt, best.depth, FULL)) {\n                best.isTemp = false;\n                best.nodeIdx = nid;\n                best.depth = depth + 1;\n                best.mt = nodes[nid].mt;\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    string ans;\n    if (best.isTemp) {\n        ans = reconstructPathFromNode(nodes, best.parent);\n        ans.push_back(best.lastMove);\n    } else {\n        ans = reconstructPathFromNode(nodes, best.nodeIdx);\n    }\n\n    if ((int)ans.size() > T) ans.resize(T);\n    cout << ans << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr double R = 10000.0;\nstatic constexpr int MAXD = 10;\n\nstruct Point {\n    int x, y;\n};\n\nstruct BestSol {\n    int score = -1;\n    int goodCells = -1;\n    int dx = 1, dy = 0;   // primitive direction vector of family 1 lines\n    int m1 = 1, m2 = 1;   // number of strips in the two directions\n    double f1 = 0.5, f2 = 0.5; // offset fractions in (0,1)\n};\n\nstatic inline bool betterScore(int sc, int good, const BestSol& best) {\n    if (sc != best.score) return sc > best.score;\n    return good > best.goodCells;\n}\n\nlong long extgcd_pos(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = 1; y = 0;\n        return a;\n    }\n    long long x1, y1;\n    long long g = extgcd_pos(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\nstatic inline int calc_bin(double v, int m, double w, double f) {\n    if (m == 1) return 0;\n    double o = w * f;\n    double first = -R + o; // first cut\n    if (v < first) return 0;\n    int b = 1 + (int)((v - first) / w + 1e-12);\n    if (b >= m - 1) b = m - 1;\n    return b;\n}\n\nstruct EvalResult {\n    int score;\n    int goodCells;\n};\n\nEvalResult evaluate_grid(\n    const vector<double>& s,\n    const vector<double>& t,\n    int m1, int m2,\n    double f1, double f2,\n    const array<int, 11>& a\n) {\n    static int cnt[3005];\n    static int hist[11];\n    int cells = m1 * m2;\n    for (int i = 0; i < cells; i++) cnt[i] = 0;\n    for (int d = 0; d <= 10; d++) hist[d] = 0;\n\n    double w1 = 2.0 * R / m1;\n    double w2 = 2.0 * R / m2;\n\n    int N = (int)s.size();\n    for (int i = 0; i < N; i++) {\n        int b1 = calc_bin(s[i], m1, w1, f1);\n        int b2 = calc_bin(t[i], m2, w2, f2);\n        cnt[b1 * m2 + b2]++;\n    }\n\n    int good = 0;\n    for (int i = 0; i < cells; i++) {\n        int c = cnt[i];\n        if (1 <= c && c <= 10) {\n            hist[c]++;\n            good++;\n        }\n    }\n\n    int score = 0;\n    for (int d = 1; d <= 10; d++) score += min(a[d], hist[d]);\n    return {score, good};\n}\n\npair<int,int> normalize_dir(int dx, int dy) {\n    if (dx == 0 && dy == 0) return {1, 0};\n    int g = std::gcd(abs(dx), abs(dy));\n    dx /= g; dy /= g;\n    if (dx < 0 || (dx == 0 && dy < 0)) {\n        dx = -dx;\n        dy = -dy;\n    }\n    return {dx, dy};\n}\n\nvector<pair<int,int>> generate_dirs() {\n    const double PI = acos(-1.0);\n    const int L = 199;\n    set<pair<int,int>> st;\n\n    for (int i = 0; i < 30; i++) {\n        double ang = PI * i / 30.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        auto p = normalize_dir(dx, dy);\n        st.insert(p);\n    }\n\n    // Add a few simple directions explicitly\n    vector<pair<int,int>> extra = {\n        {1,0}, {0,1}, {1,1}, {2,1}, {1,2}, {3,1}, {1,3}\n    };\n    for (auto [dx,dy] : extra) st.insert(normalize_dir(dx,dy));\n\n    return vector<pair<int,int>>(st.begin(), st.end());\n}\n\nvector<double> select_lambdas(int N, const array<int,11>& a) {\n    vector<pair<double,double>> cand; // (approxScore, lambda)\n    for (double lam = 0.8; lam <= 10.0 + 1e-9; lam += 0.2) {\n        double Mocc = N / lam;\n        double p = exp(-lam);\n        double score = 0.0;\n        double cur = p;\n        for (int d = 1; d <= 10; d++) {\n            cur *= lam / d;\n            double bd = Mocc * cur;\n            score += min<double>(a[d], bd);\n        }\n        cand.push_back({score, lam});\n    }\n    sort(cand.begin(), cand.end(), [&](auto &l, auto &r) {\n        return l.first > r.first;\n    });\n\n    vector<double> res;\n    for (auto [sc, lam] : cand) {\n        bool ok = true;\n        for (double x : res) {\n            if (abs(x - lam) < 0.35) { ok = false; break; }\n        }\n        if (ok) res.push_back(lam);\n        if ((int)res.size() >= 5) break;\n    }\n\n    // fallback\n    if (res.empty()) res.push_back(5.0);\n    return res;\n}\n\nvector<pair<int,int>> generate_pairs(int N, int A, const array<int,11>& a) {\n    const double PI = acos(-1.0);\n    vector<double> lambdas = select_lambdas(N, a);\n    set<pair<int,int>> st;\n\n    auto add_pair = [&](int m1, int m2) {\n        if (m1 < 1 || m2 < 1) return;\n        if (m1 + m2 - 2 > 100) return;\n        st.insert({m1, m2});\n    };\n\n    for (double lam : lambdas) {\n        double P = 4.0 * N / (PI * lam); // target total grid cells in square coords\n        vector<double> ratios = {1.0, 1.4, 1.0 / 1.4};\n\n        for (double ratio : ratios) {\n            int base1 = max(1, (int)llround(sqrt(P * ratio)));\n            for (int d1 = -2; d1 <= 2; d1++) {\n                int m1 = max(1, base1 + d1);\n                int base2 = max(1, (int)llround(P / m1));\n                for (int d2 = -1; d2 <= 1; d2++) {\n                    int m2 = max(1, base2 + d2);\n                    add_pair(m1, m2);\n                }\n            }\n        }\n    }\n\n    // Add a few 1D-ish and generic fallbacks\n    vector<int> oneD = {2,3,4,5,6,8,10,15,20,30,40,50,60,80,100};\n    for (int m : oneD) {\n        add_pair(1, m);\n        add_pair(m, 1);\n    }\n\n    // Add around sqrt(4A/pi), i.e. \"number of useful pieces ~= attendees\"\n    {\n        const double PI2 = acos(-1.0);\n        double P = 4.0 * max(1, A) / PI2;\n        int b = max(1, (int)llround(sqrt(P)));\n        for (int d1 = -3; d1 <= 3; d1++) {\n            int m1 = max(1, b + d1);\n            int m2 = max(1, (int)llround(P / m1));\n            for (int d2 = -2; d2 <= 2; d2++) add_pair(m1, m2 + d2);\n        }\n    }\n\n    vector<pair<int,int>> res(st.begin(), st.end());\n\n    // Keep a moderate number of pairs\n    sort(res.begin(), res.end(), [&](auto &L, auto &Rr) {\n        long long pL = 1LL * L.first * L.second;\n        long long pR = 1LL * Rr.first * Rr.second;\n        return pL > pR;\n    });\n    if ((int)res.size() > 90) res.resize(90);\n\n    return res;\n}\n\nvoid try_update_best(\n    BestSol& best,\n    const vector<double>& s,\n    const vector<double>& t,\n    int dx, int dy,\n    int m1, int m2,\n    double f1, double f2,\n    const array<int,11>& a\n) {\n    EvalResult e = evaluate_grid(s, t, m1, m2, f1, f2, a);\n    if (betterScore(e.score, e.goodCells, best)) {\n        best.score = e.score;\n        best.goodCells = e.goodCells;\n        best.dx = dx;\n        best.dy = dy;\n        best.m1 = m1;\n        best.m2 = m2;\n        best.f1 = f1;\n        best.f2 = f2;\n    }\n}\n\nvector<double> unique_fractions(vector<double> v) {\n    for (double &x : v) {\n        x = max(0.02, min(0.98, x));\n    }\n    sort(v.begin(), v.end());\n    vector<double> res;\n    for (double x : v) {\n        if (res.empty() || fabs(res.back() - x) > 1e-9) res.push_back(x);\n    }\n    return res;\n}\n\nlong long adjust_constant(\n    long long target,\n    long long low,\n    long long high,\n    const unordered_set<long long>& forbidden\n) {\n    for (long long d = 0; ; d++) {\n        long long c1 = target - d;\n        if (c1 >= low && c1 <= high && !forbidden.count(c1)) return c1;\n        if (d == 0) continue;\n        long long c2 = target + d;\n        if (c2 >= low && c2 <= high && !forbidden.count(c2)) return c2;\n    }\n}\n\narray<long long,4> line_from_ABC(long long A, long long B, long long C) {\n    long long aa = llabs(A), bb = llabs(B);\n    long long x, y;\n    extgcd_pos(max(1LL, aa), max(1LL, bb), x, y);\n\n    // Fix for zero coefficient cases\n    if (aa == 0) { x = 0; y = 1; }\n    else if (bb == 0) { x = 1; y = 0; }\n\n    if (A < 0) x = -x;\n    if (B < 0) y = -y;\n\n    long long x0 = x * C;\n    long long y0 = y * C;\n\n    // Shift along the line to keep coordinates small\n    long double denom = (long double)A * A + (long double)B * B;\n    long double tt = ((long double)x0 * B - (long double)y0 * A) / denom;\n    long long t = llround(tt);\n\n    x0 -= B * t;\n    y0 += A * t;\n\n    long long x1 = x0;\n    long long y1 = y0;\n    long long x2 = x0 - B;\n    long long y2 = y0 + A;\n\n    return {x1, y1, x2, y2};\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 A = 0;\n    for (int d = 1; d <= 10; d++) A += a[d];\n\n    auto pairs = generate_pairs(N, A, a);\n    auto dirs = generate_dirs();\n\n    BestSol best;\n\n    // Coarse search\n    for (auto [dx, dy] : dirs) {\n        double len = hypot((double)dx, (double)dy);\n        vector<double> s(N), t(N);\n        for (int i = 0; i < N; i++) {\n            s[i] = ((double)(-dy) * pts[i].x + (double)dx * pts[i].y) / len;\n            t[i] = ((double)dx * pts[i].x + (double)dy * pts[i].y) / len;\n        }\n\n        for (auto [m1, m2] : pairs) {\n            vector<double> fs1 = (m1 == 1 ? vector<double>{0.5} : vector<double>{0.25, 0.5, 0.75});\n            vector<double> fs2 = (m2 == 1 ? vector<double>{0.5} : vector<double>{0.25, 0.5, 0.75});\n            for (double f1 : fs1) {\n                for (double f2 : fs2) {\n                    try_update_best(best, s, t, dx, dy, m1, m2, f1, f2, a);\n                }\n            }\n        }\n    }\n\n    // Local refinement around the best\n    {\n        const double PI = acos(-1.0);\n        double ang0 = atan2((double)best.dy, (double)best.dx);\n        set<pair<int,int>> nearDirsSet;\n        const int L2 = 223;\n\n        for (int dd = -3; dd <= 3; dd++) {\n            double ang = ang0 + dd * (PI / 180.0); // \u00b13 degrees\n            int dx = (int)llround(L2 * cos(ang));\n            int dy = (int)llround(L2 * sin(ang));\n            nearDirsSet.insert(normalize_dir(dx, dy));\n        }\n        nearDirsSet.insert({best.dx, best.dy});\n\n        vector<pair<int,int>> nearDirs(nearDirsSet.begin(), nearDirsSet.end());\n\n        for (auto [dx, dy] : nearDirs) {\n            double len = hypot((double)dx, (double)dy);\n            vector<double> s(N), t(N);\n            for (int i = 0; i < N; i++) {\n                s[i] = ((double)(-dy) * pts[i].x + (double)dx * pts[i].y) / len;\n                t[i] = ((double)dx * pts[i].x + (double)dy * pts[i].y) / len;\n            }\n\n            for (int m1 = max(1, best.m1 - 2); m1 <= min(101, best.m1 + 2); m1++) {\n                for (int m2 = max(1, best.m2 - 2); m2 <= min(101, best.m2 + 2); m2++) {\n                    if (m1 + m2 - 2 > 100) continue;\n\n                    vector<double> fs1, fs2;\n                    if (m1 == 1) fs1 = {0.5};\n                    else fs1 = unique_fractions({0.25, 0.5, 0.75, best.f1 - 0.15, best.f1 - 0.07, best.f1, best.f1 + 0.07, best.f1 + 0.15});\n                    if (m2 == 1) fs2 = {0.5};\n                    else fs2 = unique_fractions({0.25, 0.5, 0.75, best.f2 - 0.15, best.f2 - 0.07, best.f2, best.f2 + 0.07, best.f2 + 0.15});\n\n                    for (double f1 : fs1) {\n                        for (double f2 : fs2) {\n                            try_update_best(best, s, t, dx, dy, m1, m2, f1, f2, a);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Reconstruct lines\n    int dx = best.dx, dy = best.dy;\n    double len = hypot((double)dx, (double)dy);\n\n    // Forbidden projected coordinates to avoid cutting strawberry centers\n    unordered_set<long long> forb1, forb2;\n    forb1.reserve(N * 2 + 10);\n    forb2.reserve(N * 2 + 10);\n    for (auto &p : pts) {\n        long long v1 = 1LL * (-dy) * p.x + 1LL * dx * p.y; // normal (-dy, dx)\n        long long v2 = 1LL * dx * p.x + 1LL * dy * p.y;    // normal (dx, dy)\n        forb1.insert(v1);\n        forb2.insert(v2);\n    }\n\n    long long lim = (long long)floor(R * len - 1e-7);\n\n    vector<array<long long,4>> out;\n\n    // Family 1: lines parallel to (dx,dy), normal A=-dy, B=dx\n    {\n        int m1 = best.m1;\n        if (m1 >= 2) {\n            double w = 2.0 * R / m1;\n            vector<long long> C(m1 - 1);\n            for (int k = 0; k < m1 - 1; k++) {\n                double c = -R + best.f1 * w + k * w; // geometric signed distance in rotated coord\n                C[k] = llround(c * len);\n            }\n            sort(C.begin(), C.end());\n            vector<long long> CC;\n            for (int i = 0; i < (int)C.size(); i++) {\n                long long low = (i == 0 ? -lim + 1 : CC.back() + 1);\n                long long high = lim - 1;\n                long long c = adjust_constant(C[i], low, high, forb1);\n                CC.push_back(c);\n            }\n            for (long long c : CC) {\n                out.push_back(line_from_ABC(-dy, dx, c));\n            }\n        }\n    }\n\n    // Family 2: lines parallel to (-dy,dx), normal A=dx, B=dy\n    {\n        int m2 = best.m2;\n        if (m2 >= 2) {\n            double w = 2.0 * R / m2;\n            vector<long long> C(m2 - 1);\n            for (int k = 0; k < m2 - 1; k++) {\n                double c = -R + best.f2 * w + k * w;\n                C[k] = llround(c * len);\n            }\n            sort(C.begin(), C.end());\n            vector<long long> CC;\n            for (int i = 0; i < (int)C.size(); i++) {\n                long long low = (i == 0 ? -lim + 1 : CC.back() + 1);\n                long long high = lim - 1;\n                long long c = adjust_constant(C[i], low, high, forb2);\n                CC.push_back(c);\n            }\n            for (long long c : CC) {\n                out.push_back(line_from_ABC(dx, dy, c));\n            }\n        }\n    }\n\n    // Safety: limit to K\n    if ((int)out.size() > K) {\n        out.resize(K);\n    }\n\n    cout << out.size() << '\\n';\n    for (auto &ln : out) {\n        cout << ln[0] << ' ' << ln[1] << ' ' << ln[2] << ' ' << ln[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nusing Op = array<int, 8>;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : 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    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Cand {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n    int gain;\n    int perim;\n    int area;\n    double eval;\n};\n\nstruct Params {\n    double beta;\n    double gamma;\n    int topKeep;\n    int pickTop;\n    double bias;\n};\n\nstruct State {\n    int N = 0;\n    uint8_t dot[MAXN][MAXN]{};\n    uint8_t H[MAXN][MAXN]{};   // (x,y) - (x+1,y)\n    uint8_t V[MAXN][MAXN]{};   // (x,y) - (x,y+1)\n    uint8_t D1[MAXN][MAXN]{};  // (x,y) - (x+1,y+1)\n    uint8_t D2[MAXN][MAXN]{};  // (x,y+1) - (x+1,y)\n    long long sumW = 0;\n    vector<Op> ops;\n};\n\nint N, M;\nint W[MAXN][MAXN];\nvector<int> cellOrder;\n\ninline int enc(int x, int y) { return (x << 6) | y; }\ninline int decx(int id) { return id >> 6; }\ninline int decy(int id) { return id & 63; }\ninline bool inside(int x, int y) { return 0 <= x && x < N && 0 <= y && y < N; }\ninline int sgn(int v) { return (v > 0) - (v < 0); }\n\ninline bool segment_used(const State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        int bx = min(x1, x2);\n        return st.H[bx][y1];\n    }\n    if (x1 == x2) {\n        int by = min(y1, y2);\n        return st.V[x1][by];\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D1[bx][by];\n    } else {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D2[bx][by];\n    }\n}\n\ninline void mark_segment(State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        int bx = min(x1, x2);\n        st.H[bx][y1] = 1;\n        return;\n    }\n    if (x1 == x2) {\n        int by = min(y1, y2);\n        st.V[x1][by] = 1;\n        return;\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        int bx = min(x1, x2), by = min(y1, y2);\n        st.D1[bx][by] = 1;\n    } else {\n        int bx = min(x1, x2), by = min(y1, y2);\n        st.D2[bx][by] = 1;\n    }\n}\n\ninline bool check_edge(const State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    if (len <= 0) return false;\n\n    int x = x1, y = y1;\n    for (int i = 1; i < len; i++) {\n        x += dx;\n        y += dy;\n        if (st.dot[x][y]) return false;\n    }\n\n    x = x1; y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        if (segment_used(st, x, y, nx, ny)) return false;\n        x = nx; y = ny;\n    }\n    return true;\n}\n\ninline void mark_edge(State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    int x = x1, y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        mark_segment(st, x, y, nx, ny);\n        x = nx; y = ny;\n    }\n}\n\ninline bool valid_rect(const State& st, const Cand& c) {\n    if (st.dot[c.x1][c.y1]) return false;\n    if (!st.dot[c.x2][c.y2] || !st.dot[c.x3][c.y3] || !st.dot[c.x4][c.y4]) return false;\n\n    if (!check_edge(st, c.x1, c.y1, c.x2, c.y2)) return false;\n    if (!check_edge(st, c.x2, c.y2, c.x3, c.y3)) return false;\n    if (!check_edge(st, c.x3, c.y3, c.x4, c.y4)) return false;\n    if (!check_edge(st, c.x4, c.y4, c.x1, c.y1)) return false;\n    return true;\n}\n\ninline void apply_move(State& st, const Cand& c) {\n    st.dot[c.x1][c.y1] = 1;\n    st.sumW += W[c.x1][c.y1];\n    mark_edge(st, c.x1, c.y1, c.x2, c.y2);\n    mark_edge(st, c.x2, c.y2, c.x3, c.y3);\n    mark_edge(st, c.x3, c.y3, c.x4, c.y4);\n    mark_edge(st, c.x4, c.y4, c.x1, c.y1);\n    st.ops.push_back({c.x1, c.y1, c.x2, c.y2, c.x3, c.y3, c.x4, c.y4});\n}\n\ninline void push_top(vector<Cand>& best, const Cand& c, int K) {\n    if ((int)best.size() < K) {\n        best.push_back(c);\n        int i = (int)best.size() - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    } else if (c.eval > best.back().eval) {\n        best.back() = c;\n        int i = K - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    }\n}\n\nint eastA[MAXN][MAXN], westA[MAXN][MAXN], northA[MAXN][MAXN], southA[MAXN][MAXN];\nint neA[MAXN][MAXN], nwA[MAXN][MAXN], seA[MAXN][MAXN], swA[MAXN][MAXN];\n\nvoid build_nearest(const State& st) {\n    for (int y = 0; y < N; y++) {\n        int last = -1;\n        for (int x = 0; x < N; x++) {\n            westA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int x = N - 1; x >= 0; x--) {\n            eastA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        int last = -1;\n        for (int y = 0; y < N; y++) {\n            southA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int y = N - 1; y >= 0; y--) {\n            northA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            swA[x][y] = (x == 0 || y == 0) ? -1\n                : (st.dot[x - 1][y - 1] ? enc(x - 1, y - 1) : swA[x - 1][y - 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = N - 1; y >= 0; y--) {\n            neA[x][y] = (x == N - 1 || y == N - 1) ? -1\n                : (st.dot[x + 1][y + 1] ? enc(x + 1, y + 1) : neA[x + 1][y + 1]);\n        }\n    }\n    for (int x = 0; x < N; x++) {\n        for (int y = N - 1; y >= 0; y--) {\n            nwA[x][y] = (x == 0 || y == N - 1) ? -1\n                : (st.dot[x - 1][y + 1] ? enc(x - 1, y + 1) : nwA[x - 1][y + 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = 0; y < N; y++) {\n            seA[x][y] = (x == N - 1 || y == 0) ? -1\n                : (st.dot[x + 1][y - 1] ? enc(x + 1, y - 1) : seA[x + 1][y - 1]);\n        }\n    }\n}\n\nvector<Cand> collect_top_candidates(const State& st, const Params& prm) {\n    build_nearest(st);\n    vector<Cand> best;\n    best.reserve(prm.topKeep);\n\n    auto try_add = [&](int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {\n        if (!inside(x3, y3)) return;\n        if (!st.dot[x3][y3]) return;\n\n        int l1 = max(abs(x2 - x1), abs(y2 - y1));\n        int l2 = max(abs(x4 - x1), abs(y4 - y1));\n        if (l1 <= 0 || l2 <= 0) return;\n\n        Cand c;\n        c.x1 = x1; c.y1 = y1;\n        c.x2 = x2; c.y2 = y2;\n        c.x3 = x3; c.y3 = y3;\n        c.x4 = x4; c.y4 = y4;\n        c.gain = W[x1][y1];\n        c.perim = 2 * (l1 + l2);\n        c.area = l1 * l2;\n        c.eval = c.gain - prm.beta * c.perim - prm.gamma * c.area;\n\n        if (valid_rect(st, c)) push_top(best, c, prm.topKeep);\n    };\n\n    for (int id : cellOrder) {\n        int x = decx(id), y = decy(id);\n        if (st.dot[x][y]) continue;\n\n        int e = eastA[x][y], w = westA[x][y], n = northA[x][y], s = southA[x][y];\n        int ne = neA[x][y], nw = nwA[x][y], se = seA[x][y], sw = swA[x][y];\n\n        // Axis-aligned\n        if (e != -1 && n != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (e != -1 && s != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (w != -1 && n != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (w != -1 && s != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n\n        // 45-degree rectangles\n        if (ne != -1 && nw != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (ne != -1 && se != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (sw != -1 && nw != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (sw != -1 && se != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n    }\n\n    return best;\n}\n\nint choose_idx(const vector<Cand>& cand, const Params& prm, XorShift64& rng) {\n    if (cand.empty()) return -1;\n    int m = min((int)cand.size(), prm.pickTop);\n    if (m <= 1) return 0;\n    double r = rng.next_double();\n    int idx = (int)(pow(r, prm.bias) * m);\n    if (idx >= m) idx = m - 1;\n    return idx;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State initial;\n    initial.N = N;\n    initial.ops.reserve(N * N);\n\n    vector<pair<int,int>> initPts;\n    initPts.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        initial.dot[x][y] = 1;\n        initPts.push_back({x, y});\n    }\n\n    int c = (N - 1) / 2;\n    cellOrder.clear();\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            W[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n            cellOrder.push_back(enc(x, y));\n        }\n    }\n    sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n        int xa = decx(a), ya = decy(a);\n        int xb = decx(b), yb = decy(b);\n        if (W[xa][ya] != W[xb][yb]) return W[xa][ya] > W[xb][yb];\n        if (xa != xb) return xa < xb;\n        return ya < yb;\n    });\n\n    initial.sumW = 0;\n    for (auto [x, y] : initPts) initial.sumW += W[x][y];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    for (auto [x, y] : initPts) {\n        seed ^= (uint64_t)(x * 131 + y) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n    XorShift64 rng(seed);\n\n    vector<Params> presets = {\n        {0.10, 0.005, 40, 1, 1.0},\n        {0.25, 0.020, 40, 3, 2.0},\n        {0.45, 0.040, 50, 5, 2.5},\n        {0.70, 0.070, 60, 8, 3.0},\n    };\n\n    auto st_time = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st_time).count();\n    };\n    const double TL = 4.6;\n\n    long long bestSum = initial.sumW;\n    vector<Op> bestOps;\n\n    int run = 0;\n    while (elapsed() < TL) {\n        Params prm = presets[run % presets.size()];\n        if (run >= (int)presets.size()) {\n            prm.beta *= 0.75 + 0.70 * rng.next_double();\n            prm.gamma *= 0.75 + 0.70 * rng.next_double();\n            prm.pickTop = max(1, min(prm.topKeep, prm.pickTop + (int)(rng.next_u32() % 3) - 1));\n            prm.bias *= 0.85 + 0.40 * rng.next_double();\n        }\n\n        State st = initial;\n        st.ops.clear();\n        st.ops.reserve(N * N);\n\n        while (elapsed() < TL) {\n            auto cand = collect_top_candidates(st, prm);\n            if (cand.empty()) break;\n            int idx = choose_idx(cand, prm, rng);\n            apply_move(st, cand[idx]);\n        }\n\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n        run++;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto& op : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << op[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() {\n        return static_cast<uint32_t>(next_u64());\n    }\n};\n\nstruct Board {\n    array<uint8_t, 100> a;\n    Board() { a.fill(0); }\n};\n\nstatic constexpr int N = 10;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\nstruct Solver {\n    array<int, 101> f{};\n    Board board;\n    int target_type_of_flavor[4]{}; // flavor 1..3 -> 0:TL, 1:TR, 2:BC\n    int dist_table[3][100]{};\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    Solver() {\n        start_time = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void init_dist_table() {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int idx = r * N + c;\n                // top-left\n                dist_table[0][idx] = r + c;\n                // top-right\n                dist_table[1][idx] = r + (N - 1 - c);\n                // bottom-center (between columns 4 and 5)\n                dist_table[2][idx] = (N - 1 - r) + min(abs(c - 4), abs(c - 5));\n            }\n        }\n    }\n\n    void read_flavors() {\n        uint64_t seed = 1469598103934665603ull;\n        for (int i = 1; i <= 100; i++) {\n            cin >> f[i];\n            seed ^= (uint64_t)(f[i] + 1009 * i);\n            seed *= 1099511628211ull;\n        }\n        rng = XorShift64(seed ^ 0x9e3779b97f4a7c15ull);\n        init_dist_table();\n    }\n\n    static inline void place(Board &b, int p, int flavor) {\n        int cnt = 0;\n        for (int i = 0; i < 100; i++) {\n            if (b.a[i] == 0) {\n                ++cnt;\n                if (cnt == p) {\n                    b.a[i] = (uint8_t)flavor;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline Board tilt(const Board &in, int dir) {\n        Board out;\n        if (dir == 0) { // F: up\n            for (int c = 0; c < N; c++) {\n                int wr = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr++ * N + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B: down\n            for (int c = 0; c < N; c++) {\n                int wr = N - 1;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr-- * N + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                int wc = 0;\n                int base = r * N;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc++] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < N; r++) {\n                int wc = N - 1;\n                int base = r * N;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc--] = v;\n                }\n            }\n        }\n        return out;\n    }\n\n    static inline int component_square_sum(const Board &b) {\n        bool vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; s++) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            int qh = 0, qt = 0;\n            q[qt++] = s;\n            vis[s] = true;\n            int sz = 0;\n\n            while (qh < qt) {\n                int v = q[qh++];\n                ++sz;\n                int r = v / N, c = v % N;\n\n                if (r > 0) {\n                    int nv = v - N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (r + 1 < N) {\n                    int nv = v + N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c + 1 < N) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    inline int heuristic(const Board &b) const {\n        int rowcnt[10][4] = {};\n        int colcnt[10][4] = {};\n        int same_adj = 0, diff_adj = 0;\n        int dist_pen = 0;\n\n        for (int idx = 0; idx < 100; idx++) {\n            uint8_t col = b.a[idx];\n            if (!col) continue;\n            int r = idx / N, c = idx % N;\n            rowcnt[r][col]++;\n            colcnt[c][col]++;\n            dist_pen += dist_table[target_type_of_flavor[col]][idx];\n\n            if (c + 1 < N) {\n                uint8_t v = b.a[idx + 1];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t v = b.a[idx + N];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n        }\n\n        int purity = 0;\n        for (int i = 0; i < N; i++) {\n            for (int col = 1; col <= 3; col++) {\n                purity += rowcnt[i][col] * rowcnt[i][col];\n                purity += colcnt[i][col] * colcnt[i][col];\n            }\n        }\n\n        int comp2 = component_square_sum(b);\n\n        // Tuned by hand for a balanced behavior.\n        return 20 * comp2 + 8 * same_adj - 6 * diff_adj + 2 * purity - 3 * dist_pen;\n    }\n\n    inline int greedy_action(const Board &b) const {\n        int best_dir = 0;\n        int best_score = numeric_limits<int>::min();\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(b, dir);\n            int sc = heuristic(nb);\n            if (sc > best_score) {\n                best_score = sc;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void choose_best_mapping() {\n        // Pre-sample placement sequences for fair comparison of all 6 assignments.\n        const int TRIALS = 8;\n        int sampled_p[TRIALS][101]{};\n        for (int t = 0; t < TRIALS; t++) {\n            for (int turn = 1; turn <= 100; turn++) {\n                int empties = 101 - turn;\n                sampled_p[t][turn] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        array<int, 3> perm = {0, 1, 2};\n        long long best_total = -1;\n        int best_map[4] = {0, 0, 1, 2};\n\n        do {\n            target_type_of_flavor[1] = perm[0];\n            target_type_of_flavor[2] = perm[1];\n            target_type_of_flavor[3] = perm[2];\n\n            long long total = 0;\n            for (int tr = 0; tr < TRIALS; tr++) {\n                Board b;\n                for (int turn = 1; turn <= 100; turn++) {\n                    place(b, sampled_p[tr][turn], f[turn]);\n                    int act = greedy_action(b);\n                    b = tilt(b, act);\n                }\n                total += component_square_sum(b);\n            }\n\n            if (total > best_total) {\n                best_total = total;\n                for (int c = 1; c <= 3; c++) best_map[c] = target_type_of_flavor[c];\n            }\n        } while (next_permutation(perm.begin(), perm.end()));\n\n        for (int c = 1; c <= 3; c++) target_type_of_flavor[c] = best_map[c];\n    }\n\n    int rollout_count(int rem_future) const {\n        int k;\n        if (rem_future > 70) k = 4;\n        else if (rem_future > 40) k = 6;\n        else if (rem_future > 20) k = 10;\n        else k = 16;\n\n        double t = elapsed();\n        if (t > 1.70) k = min(k, 4);\n        if (t > 1.90) k = 1;\n        return k;\n    }\n\n    int decide_action(int turn) {\n        int rem_future = 100 - turn;\n\n        // Final turn: exact immediate choice.\n        if (rem_future == 0) {\n            int best_dir = 0;\n            int best_score = -1;\n            int best_h = numeric_limits<int>::min();\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(board, dir);\n                int sc = component_square_sum(nb);\n                int h = heuristic(nb);\n                if (sc > best_score || (sc == best_score && h > best_h)) {\n                    best_score = sc;\n                    best_h = h;\n                    best_dir = dir;\n                }\n            }\n            return best_dir;\n        }\n\n        int K = rollout_count(rem_future);\n\n        // Pre-sample future placement indices for variance reduction across actions.\n        static int sampled_p[20][100];\n        for (int k = 0; k < K; k++) {\n            for (int step = 0; step < rem_future; step++) {\n                int empties = rem_future - step;\n                sampled_p[k][step] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        long long best_sum = -1;\n        int best_dir = 0;\n        int best_h = numeric_limits<int>::min();\n\n        for (int dir = 0; dir < 4; dir++) {\n            Board start = tilt(board, dir);\n            long long total = 0;\n\n            for (int k = 0; k < K; k++) {\n                Board b = start;\n                for (int step = 0; step < rem_future; step++) {\n                    int future_turn = turn + 1 + step;\n                    place(b, sampled_p[k][step], f[future_turn]);\n                    int act = greedy_action(b);\n                    b = tilt(b, act);\n                }\n                total += component_square_sum(b);\n            }\n\n            int h = heuristic(start);\n            if (total > best_sum || (total == best_sum && h > best_h)) {\n                best_sum = total;\n                best_h = h;\n                best_dir = dir;\n            }\n        }\n\n        return best_dir;\n    }\n\n    void solve() {\n        read_flavors();\n        choose_best_mapping();\n\n        for (int turn = 1; turn <= 100; turn++) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place(board, p, f[turn]);\n            int dir = decide_action(turn);\n            board = tilt(board, dir);\n\n            cout << DIR_CH[dir] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct ExactNoNoiseSolver {\n    int M, N, C;\n    vector<vector<int>> perm_maps;          // perm_maps[p][old_edge_idx] = new_edge_idx\n    vector<uint32_t> reps;                  // chosen canonical masks\n    unordered_map<uint32_t, int> id_of;     // canonical mask -> index\n\n    static int unlabeled_count(int n) {\n        if (n == 4) return 11;\n        if (n == 5) return 34;\n        if (n == 6) return 156;\n        return 0;\n    }\n\n    static vector<pair<int,int>> edge_list(int n) {\n        vector<pair<int,int>> e;\n        for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) e.push_back({i, j});\n        return e;\n    }\n\n    uint32_t permute_mask(uint32_t mask, const vector<int>& mp) const {\n        uint32_t res = 0;\n        while (mask) {\n            int b = __builtin_ctz(mask);\n            mask &= mask - 1;\n            res |= (1u << mp[b]);\n        }\n        return res;\n    }\n\n    uint32_t canonical(uint32_t mask) const {\n        uint32_t best = UINT32_MAX;\n        for (const auto& mp : perm_maps) {\n            uint32_t x = permute_mask(mask, mp);\n            if (x < best) best = x;\n        }\n        return best;\n    }\n\n    string mask_to_string(uint32_t mask) const {\n        string s;\n        s.reserve(C);\n        for (int i = 0; i < C; ++i) s.push_back(((mask >> i) & 1u) ? '1' : '0');\n        return s;\n    }\n\n    uint32_t string_to_mask(const string& s) const {\n        uint32_t mask = 0;\n        for (int i = 0; i < (int)s.size(); ++i) if (s[i] == '1') mask |= (1u << i);\n        return mask;\n    }\n\n    ExactNoNoiseSolver(int M_) : M(M_) {\n        if (M <= unlabeled_count(4)) N = 4;\n        else if (M <= unlabeled_count(5)) N = 5;\n        else N = 6;\n        C = N * (N - 1) / 2;\n\n        auto edges = edge_list(N);\n        vector<vector<int>> pos(N, vector<int>(N, -1));\n        for (int i = 0; i < C; ++i) {\n            auto [u, v] = edges[i];\n            pos[u][v] = pos[v][u] = i;\n        }\n\n        vector<int> p(N);\n        iota(p.begin(), p.end(), 0);\n        do {\n            vector<int> mp(C);\n            for (int i = 0; i < C; ++i) {\n                auto [u, v] = edges[i];\n                int a = p[u], b = p[v];\n                if (a > b) swap(a, b);\n                mp[i] = pos[a][b];\n            }\n            perm_maps.push_back(move(mp));\n        } while (next_permutation(p.begin(), p.end()));\n\n        set<uint32_t> seen;\n        uint32_t total = 1u << C;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            uint32_t can = canonical(mask);\n            if (seen.insert(can).second) reps.push_back(can);\n        }\n        sort(reps.begin(), reps.end());\n        reps.resize(M);\n        for (int i = 0; i < M; ++i) id_of[reps[i]] = i;\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (uint32_t m : reps) cout << mask_to_string(m) << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        uint32_t mask = string_to_mask(H);\n        uint32_t can = canonical(mask);\n        auto it = id_of.find(can);\n        if (it == id_of.end()) return 0;\n        return it->second;\n    }\n};\n\nstruct Candidate {\n    uint32_t mask;\n    vector<int> seq; // sorted block degrees, length R\n};\n\nstruct GeneralSolver {\n    int M;\n    double eps, a, c;\n    int R, B, N;\n\n    vector<uint32_t> masks;\n    vector<string> graphs;\n    vector<vector<int>> ideals; // sorted ideal full degree sequence, length N per graph\n\n    static int seq_dist2(const vector<int>& x, const vector<int>& y) {\n        int s = 0;\n        for (int i = 0; i < (int)x.size(); ++i) {\n            int d = x[i] - y[i];\n            s += d * d;\n        }\n        return s;\n    }\n\n    static vector<int> block_degree_seq(uint32_t mask, int R, int B) {\n        vector<int> deg(R);\n        int suf = 0;\n        for (int i = R - 1; i >= 0; --i) {\n            int z = (mask >> i) & 1u;\n            deg[i] = B * suf + (z ? (B - 1 + B * i) : 0);\n            suf += z;\n        }\n        sort(deg.begin(), deg.end());\n        return deg;\n    }\n\n    static string build_graph_string(uint32_t mask, int R, int B) {\n        int N = R * B;\n        string g;\n        g.reserve(N * (N - 1) / 2);\n        for (int u = 0; u < N; ++u) {\n            int bu = u / B;\n            for (int v = u + 1; v < N; ++v) {\n                int bv = v / B;\n                bool e;\n                if (bu == bv) e = ((mask >> bu) & 1u);\n                else e = ((mask >> bv) & 1u); // later block decides\n                g.push_back(e ? '1' : '0');\n            }\n        }\n        return g;\n    }\n\n    struct ComboResult {\n        double proxy = -1.0;\n        int R = -1, B = -1, N = -1;\n        vector<Candidate> selected;\n    };\n\n    double eval_proxy(const vector<Candidate>& sel, int R, int B) const {\n        int N = R * B;\n        double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n        double avg_p = 0.0;\n        const double SQRT2 = sqrt(2.0);\n\n        for (int i = 0; i < M; ++i) {\n            int best_d2 = INT_MAX;\n            for (int j = 0; j < M; ++j) if (i != j) {\n                best_d2 = min(best_d2, seq_dist2(sel[i].seq, sel[j].seq));\n            }\n            double p = 0.0;\n            if (sigma > 1e-15) {\n                double D = a * sqrt((double)B * best_d2);\n                double x = D / (2.0 * sigma);\n                p = 0.5 * erfc(x / SQRT2);\n            }\n            avg_p += p;\n        }\n        avg_p /= M;\n\n        double per_query = max(0.0, 1.0 - 0.1 * avg_p);\n        return pow(per_query, 100.0) / N;\n    }\n\n    vector<Candidate> greedy_select(const vector<Candidate>& cands, int start_idx) const {\n        int C = (int)cands.size();\n        vector<int> minD(C, INT_MAX);\n        vector<char> used(C, 0);\n        vector<int> sel_idx;\n        sel_idx.reserve(M);\n\n        auto add_one = [&](int idx) {\n            used[idx] = 1;\n            sel_idx.push_back(idx);\n            for (int i = 0; i < C; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[idx].seq, cands[i].seq);\n                if (d2 < minD[i]) minD[i] = d2;\n            }\n        };\n\n        add_one(start_idx);\n        if (M >= 2) {\n            int far = -1, far_d = -1;\n            for (int i = 0; i < C; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[start_idx].seq, cands[i].seq);\n                if (d2 > far_d) far_d = d2, far = i;\n            }\n            add_one(far);\n        }\n\n        while ((int)sel_idx.size() < M) {\n            int best = -1, best_d = -1;\n            for (int i = 0; i < C; ++i) if (!used[i]) {\n                if (minD[i] > best_d) {\n                    best_d = minD[i];\n                    best = i;\n                }\n            }\n            add_one(best);\n        }\n\n        vector<Candidate> sel;\n        sel.reserve(M);\n        for (int idx : sel_idx) sel.push_back(cands[idx]);\n        sort(sel.begin(), sel.end(), [](const Candidate& lhs, const Candidate& rhs) {\n            return lhs.seq < rhs.seq;\n        });\n        return sel;\n    }\n\n    ComboResult try_combo(int R, int B) const {\n        ComboResult res;\n        res.R = R;\n        res.B = B;\n        res.N = R * B;\n\n        map<vector<int>, uint32_t> uniq;\n        uint32_t total = 1u << R;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            vector<int> seq = block_degree_seq(mask, R, B);\n            if (!uniq.count(seq)) uniq.emplace(seq, mask);\n        }\n\n        vector<Candidate> cands;\n        cands.reserve(uniq.size());\n        for (auto& kv : uniq) cands.push_back({kv.second, kv.first});\n        if ((int)cands.size() < M) return res;\n\n        int C = (int)cands.size();\n        vector<int> sums(C);\n        for (int i = 0; i < C; ++i) {\n            sums[i] = accumulate(cands[i].seq.begin(), cands[i].seq.end(), 0);\n        }\n\n        int min_idx = 0, max_idx = 0;\n        for (int i = 1; i < C; ++i) {\n            if (sums[i] < sums[min_idx]) min_idx = i;\n            if (sums[i] > sums[max_idx]) max_idx = i;\n        }\n        vector<pair<int,int>> ord;\n        ord.reserve(C);\n        for (int i = 0; i < C; ++i) ord.push_back({sums[i], i});\n        sort(ord.begin(), ord.end());\n        int med_idx = ord[C / 2].second;\n\n        vector<int> starts = {min_idx, max_idx, med_idx};\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int st : starts) {\n            vector<Candidate> sel = greedy_select(cands, st);\n            double pr = eval_proxy(sel, R, B);\n            if (pr > res.proxy) {\n                res.proxy = pr;\n                res.selected = move(sel);\n            }\n        }\n        return res;\n    }\n\n    GeneralSolver(int M_, double eps_) : M(M_), eps(eps_) {\n        a = 1.0 - 2.0 * eps;\n        c = eps * 0.0; // set later once N is fixed\n\n        ComboResult best;\n\n        int minR = 0;\n        while ((1u << minR) < (unsigned)M) ++minR;\n        minR = max(minR, 4);\n        int maxR = min(12, minR + 5);\n\n        for (int r = minR; r <= maxR; ++r) {\n            int maxB = 100 / r;\n            for (int b = 1; b <= maxB; ++b) {\n                ComboResult cur = try_combo(r, b);\n                if (cur.proxy > best.proxy) best = move(cur);\n            }\n        }\n\n        if (best.proxy < 0) {\n            // very conservative fallback\n            R = minR;\n            B = max(1, 100 / R);\n            N = R * B;\n            c = eps * (N - 1);\n            for (int k = 0; k < M; ++k) {\n                uint32_t mask = (uint32_t)k;\n                masks.push_back(mask);\n                graphs.push_back(build_graph_string(mask, R, B));\n                auto seq = block_degree_seq(mask, R, B);\n                vector<int> full;\n                full.reserve(N);\n                for (int d : seq) for (int t = 0; t < B; ++t) full.push_back(d);\n                ideals.push_back(move(full));\n            }\n            return;\n        }\n\n        R = best.R;\n        B = best.B;\n        N = best.N;\n        c = eps * (N - 1);\n\n        for (const auto& cand : best.selected) {\n            masks.push_back(cand.mask);\n            graphs.push_back(build_graph_string(cand.mask, R, B));\n            vector<int> full;\n            full.reserve(N);\n            for (int d : cand.seq) for (int t = 0; t < B; ++t) full.push_back(d);\n            ideals.push_back(move(full));\n        }\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (const string& g : graphs) cout << g << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        vector<int> deg(N, 0);\n        int p = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                if (H[p++] == '1') {\n                    ++deg[i];\n                    ++deg[j];\n                }\n            }\n        }\n        sort(deg.begin(), deg.end());\n\n        int best_id = 0;\n        double best_cost = 1e300;\n        for (int k = 0; k < M; ++k) {\n            const auto& ideal = ideals[k];\n            double cost = 0.0;\n            for (int i = 0; i < N; ++i) {\n                double diff = (deg[i] - c) - a * ideal[i];\n                cost += diff * diff;\n            }\n            if (cost < best_cost) {\n                best_cost = cost;\n                best_id = k;\n            }\n        }\n        return best_id;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    if (fabs(eps) < 1e-12) {\n        ExactNoNoiseSolver solver(M);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        GeneralSolver solver(M, eps);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\nstatic const int MAXD = 30;\n\nstruct Solver {\n    struct Edge {\n        int u, v;\n        ll w;\n        int cell = 0;\n        double usage = 0.0;\n        ll detour = 0;\n        double imp = 1.0;\n    };\n    struct Adj {\n        int to, id;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<pair<int,int>> coord;\n    vector<vector<Adj>> g;\n\n    // assignment\n    vector<int> dayOf;                 // edge -> day [0..D-1]\n    vector<int> posInDay;\n    vector<vector<int>> dayEdges;\n    vector<int> quota;\n    vector<int> dayCnt;\n    vector<double> dayLoad;            // sum of importance\n\n    // penalties\n    vector<array<int, MAXD>> cntV;     // vertex x day\n    vector<array<int, MAXD>> cntCell;  // cell x day\n    int G;                             // grid size\n    int C;                             // number of cells\n\n    // weights for proxy objective\n    double WA, WB, WC;\n\n    // landmarks / sampled evaluation\n    vector<int> landmarks;\n    int L_imp = 16;\n    int L_eval = 6;\n    vector<vector<ll>> origEvalDist;   // [L_eval][N]\n    vector<ll> dayScore;               // sampled true-ish score per day\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    Solver() {\n        rng.seed((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n        st = chrono::steady_clock::now();\n    }\n\n    inline double comb2(int x) const {\n        return 0.5 * x * (x - 1);\n    }\n\n    void read_input() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            ll w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i] = {u, v, w};\n            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n        }\n        coord.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> coord[i].first >> coord[i].second;\n        }\n\n        G = max(4, min(6, (int)llround(sqrt((double)D)) + 1));\n        C = G * G;\n\n        for (int i = 0; i < M; i++) {\n            double mx = (coord[edges[i].u].first + coord[edges[i].v].first) * 0.5;\n            double my = (coord[edges[i].u].second + coord[edges[i].v].second) * 0.5;\n            int cx = min(G - 1, max(0, (int)(mx * G / 1001.0)));\n            int cy = min(G - 1, max(0, (int)(my * G / 1001.0)));\n            edges[i].cell = cy * G + cx;\n        }\n\n        dayOf.assign(M, -1);\n        posInDay.assign(M, -1);\n        dayEdges.assign(D, {});\n        quota.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) quota[d]++;\n        dayCnt.assign(D, 0);\n        dayLoad.assign(D, 0.0);\n\n        cntV.assign(N, {});\n        for (auto &a : cntV) a.fill(0);\n        cntCell.assign(C, {});\n        for (auto &a : cntCell) a.fill(0);\n\n        // proxy weights\n        // day-load balance, same-vertex collision, same-cell collision\n        WA = 0.02;\n        WB = 4.0;\n        WC = 0.5;\n    }\n\n    // Dijkstra. If needParent=true, fill parV/parE with one shortest path tree.\n    void dijkstra_full(int src,\n                       vector<ll> &dist,\n                       int skipEdge = -1,\n                       int skipDay = -1,\n                       int target = -1,\n                       vector<int> *parV = nullptr,\n                       vector<int> *parE = nullptr) {\n        dist.assign(N, INF64);\n        if (parV) parV->assign(N, -1);\n        if (parE) parE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n            if (v == target) return;\n\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == skipEdge) continue;\n                if (skipDay >= 0 && dayOf[id] == skipDay) continue;\n\n                int to = ad.to;\n                ll nd = cd + edges[id].w;\n\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parV) (*parV)[to] = v;\n                    if (parE) (*parE)[to] = id;\n                    pq.push({nd, to});\n                } else if (parE && nd == dist[to]) {\n                    if ((*parE)[to] == -1 || id < (*parE)[to]) {\n                        (*parV)[to] = v;\n                        (*parE)[to] = id;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> choose_landmarks(int L) {\n        L = min(L, N);\n        vector<int> res;\n        res.reserve(L);\n\n        vector<ll> best(N, (1LL << 62));\n        int first = 0;\n        res.push_back(first);\n\n        auto dist2 = [&](int a, int b) -> ll {\n            ll dx = coord[a].first - coord[b].first;\n            ll dy = coord[a].second - coord[b].second;\n            return dx * dx + dy * dy;\n        };\n\n        for (int i = 0; i < N; i++) best[i] = dist2(i, first);\n\n        while ((int)res.size() < L) {\n            int cand = -1;\n            ll val = -1;\n            for (int i = 0; i < N; i++) {\n                if (best[i] > val) {\n                    val = best[i];\n                    cand = i;\n                }\n            }\n            res.push_back(cand);\n            for (int i = 0; i < N; i++) {\n                best[i] = min(best[i], dist2(i, cand));\n            }\n        }\n        return res;\n    }\n\n    void compute_importance() {\n        landmarks = choose_landmarks(L_imp);\n        L_imp = (int)landmarks.size();\n        L_eval = min(L_eval, L_imp);\n\n        origEvalDist.assign(L_eval, vector<ll>(N, INF64));\n\n        // usage from shortest path trees\n        vector<ll> dist;\n        vector<int> parV, parE;\n        for (int li = 0; li < L_imp; li++) {\n            int s = landmarks[li];\n            dijkstra_full(s, dist, -1, -1, -1, &parV, &parE);\n\n            if (li < L_eval) {\n                origEvalDist[li] = dist;\n            }\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sz(N, 1);\n            for (int v : ord) {\n                if (v == s) continue;\n                int pe = parE[v];\n                int pv = parV[v];\n                if (pe >= 0) {\n                    edges[pe].usage += sz[v];\n                    sz[pv] += sz[v];\n                }\n            }\n        }\n\n        // detour: distance between endpoints without that edge\n        vector<ll> dist2;\n        for (int eid = 0; eid < M; eid++) {\n            int s = edges[eid].u;\n            int t = edges[eid].v;\n            dijkstra_full(s, dist2, eid, -1, t, nullptr, nullptr);\n            ll alt = dist2[t];\n            if (alt >= INF64 / 2) alt = (ll)1e18; // should not happen in 2-edge-connected graph\n            edges[eid].detour = max<ll>(0, alt - edges[eid].w);\n        }\n\n        double avgUsage = 0.0;\n        double avgDet = 0.0;\n        for (int i = 0; i < M; i++) {\n            avgUsage += edges[i].usage + 1.0;\n            avgDet += (double)edges[i].detour + 1.0;\n        }\n        avgUsage /= M;\n        avgDet /= M;\n\n        double meanRaw = 0.0;\n        vector<double> raw(M);\n        for (int i = 0; i < M; i++) {\n            double u = (edges[i].usage + 1.0) / avgUsage;\n            double d = ((double)edges[i].detour + 1.0) / avgDet;\n            raw[i] = u * d;\n            meanRaw += raw[i];\n        }\n        meanRaw /= M;\n        if (meanRaw <= 0) meanRaw = 1.0;\n\n        for (int i = 0; i < M; i++) {\n            edges[i].imp = raw[i] / meanRaw;\n        }\n    }\n\n    inline double greedy_add_cost(int eid, int d) const {\n        const auto &e = edges[eid];\n        double x = e.imp;\n        double cost = 0.0;\n        cost += WA * (2.0 * dayLoad[d] * x + x * x);\n        cost += WB * (cntV[e.u][d] + cntV[e.v][d]);\n        cost += WC * (cntCell[e.cell][d]);\n        return cost;\n    }\n\n    void assign_initial(int eid, int d) {\n        dayOf[eid] = d;\n        posInDay[eid] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(eid);\n        dayCnt[d]++;\n        dayLoad[d] += edges[eid].imp;\n        cntV[edges[eid].u][d]++;\n        cntV[edges[eid].v][d]++;\n        cntCell[edges[eid].cell][d]++;\n    }\n\n    void build_initial_solution() {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (edges[a].imp != edges[b].imp) return edges[a].imp > edges[b].imp;\n            return a < b;\n        });\n\n        for (int eid : ord) {\n            double bestCost = 1e100;\n            int bestDay = -1;\n\n            vector<int> days(D);\n            iota(days.begin(), days.end(), 0);\n            shuffle(days.begin(), days.end(), rng);\n\n            for (int d : days) {\n                if (dayCnt[d] >= quota[d]) continue;\n                double c = greedy_add_cost(eid, d);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestDay = d;\n                }\n            }\n            if (bestDay == -1) {\n                for (int d = 0; d < D; d++) {\n                    if (dayCnt[d] < quota[d]) {\n                        bestDay = d;\n                        break;\n                    }\n                }\n            }\n            assign_initial(eid, bestDay);\n        }\n    }\n\n    void move_edge_day(int eid, int nd) {\n        int od = dayOf[eid];\n        if (od == nd) return;\n\n        // remove from old day vector\n        int pos = posInDay[eid];\n        int last = dayEdges[od].back();\n        dayEdges[od][pos] = last;\n        posInDay[last] = pos;\n        dayEdges[od].pop_back();\n\n        // add to new\n        posInDay[eid] = (int)dayEdges[nd].size();\n        dayEdges[nd].push_back(eid);\n\n        // counts\n        dayCnt[od]--;\n        dayCnt[nd]++;\n        dayLoad[od] -= edges[eid].imp;\n        dayLoad[nd] += edges[eid].imp;\n\n        cntV[edges[eid].u][od]--;\n        cntV[edges[eid].v][od]--;\n        cntV[edges[eid].u][nd]++;\n        cntV[edges[eid].v][nd]++;\n\n        cntCell[edges[eid].cell][od]--;\n        cntCell[edges[eid].cell][nd]++;\n\n        dayOf[eid] = nd;\n    }\n\n    void apply_swap(int e1, int e2) {\n        int d1 = dayOf[e1], d2 = dayOf[e2];\n        if (d1 == d2) return;\n        move_edge_day(e1, d2);\n        move_edge_day(e2, d1);\n    }\n\n    double proxy_swap_delta(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return 0.0;\n\n        const auto &E1 = edges[e1];\n        const auto &E2 = edges[e2];\n\n        double delta = 0.0;\n\n        // load term\n        {\n            double la = dayLoad[a], lb = dayLoad[b];\n            double x = E1.imp, y = E2.imp;\n            double nla = la - x + y;\n            double nlb = lb - y + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n\n        // vertex term\n        {\n            int vs[4] = {E1.u, E1.v, E2.u, E2.v};\n            sort(vs, vs + 4);\n            int m = unique(vs, vs + 4) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][a];\n                int cb = cntV[v][b];\n                int da = 0;\n                if (E1.u == v || E1.v == v) da--;\n                if (E2.u == v || E2.v == v) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WB * add;\n        }\n\n        // cell term\n        {\n            int cs[2] = {E1.cell, E2.cell};\n            sort(cs, cs + 2);\n            int m = unique(cs, cs + 2) - cs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int c = cs[i];\n                int ca = cntCell[c][a];\n                int cb = cntCell[c][b];\n                int da = 0;\n                if (E1.cell == c) da--;\n                if (E2.cell == c) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WC * add;\n        }\n\n        return delta;\n    }\n\n    int pick_edge_from_day(int d, bool highImp) {\n        const auto &vec = dayEdges[d];\n        int sz = (int)vec.size();\n        if (sz == 0) return -1;\n        int best = vec[rng() % sz];\n        for (int t = 0; t < 2; t++) {\n            int cand = vec[rng() % sz];\n            if (highImp) {\n                if (edges[cand].imp > edges[best].imp) best = cand;\n            } else {\n                if (edges[cand].imp < edges[best].imp) best = cand;\n            }\n        }\n        return best;\n    }\n\n    void proxy_local_search(double timeLimit) {\n        int it = 0;\n        while (elapsed() < timeLimit) {\n            it++;\n\n            int a = rng() % D;\n            int b = rng() % D;\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n            // make a somewhat heavier day donate an important edge\n            if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n\n            double delta = proxy_swap_delta(e1, e2);\n            if (delta < 0.0) {\n                apply_swap(e1, e2);\n            }\n        }\n    }\n\n    ll eval_day_score(int blockedDay) {\n        vector<ll> dist;\n        ll total = 0;\n        for (int si = 0; si < L_eval; si++) {\n            dijkstra_full(landmarks[si], dist, -1, blockedDay, -1, nullptr, nullptr);\n            for (int v = 0; v < N; v++) {\n                ll dv = (dist[v] >= INF64 / 2 ? (ll)1e9 : dist[v]);\n                total += dv - origEvalDist[si][v];\n            }\n        }\n        return total;\n    }\n\n    void sampled_local_search(double timeLimit) {\n        dayScore.assign(D, 0);\n        for (int d = 0; d < D; d++) dayScore[d] = eval_day_score(d);\n\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n\n        int evalCnt = 0;\n        const int MAX_EVAL = 400;\n\n        while (elapsed() < timeLimit && evalCnt < MAX_EVAL) {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dayScore[a] > dayScore[b];\n            });\n\n            int topk = min(4, D);\n            int botk = min(4, D);\n            int a = ord[rng() % topk];\n            int b = ord[D - 1 - (rng() % botk)];\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n\n            double pdelta = proxy_swap_delta(e1, e2);\n            if (pdelta > 2.0 && (rng() & 3)) continue;\n\n            ll oldScore = dayScore[a] + dayScore[b];\n\n            apply_swap(e1, e2);\n            ll na = eval_day_score(a);\n            ll nb = eval_day_score(b);\n            evalCnt++;\n\n            ll newScore = na + nb;\n            if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                dayScore[a] = na;\n                dayScore[b] = nb;\n            } else {\n                apply_swap(e1, e2); // revert\n            }\n        }\n    }\n\n    void solve() {\n        read_input();\n        compute_importance();\n        build_initial_solution();\n\n        // fast proxy improvement\n        if (elapsed() < 2.2) {\n            proxy_local_search(2.2);\n        }\n\n        // closer-to-true improvement with sampled Dijkstra\n        if (elapsed() < 5.6) {\n            sampled_local_search(5.6);\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << (dayOf[i] + 1);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp(int nL = 0, int nR = 0) : nL(nL), nR(nR), g(nL) {}\n\n    void add_edge(int u, int v) {\n        g[u].push_back(v);\n    }\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();\n            q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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)) {\n                    ++matching;\n                }\n            }\n        }\n        return matching;\n    }\n};\n\nstruct Construction {\n    vector<char> occ;              // size D^3\n    vector<int> occLins;           // occupied linear indices\n    vector<pair<int,int>> doms;    // matched domino pairs (linear indices)\n    int V = 0;\n    string name;\n};\n\nstruct ObjData {\n    int D;\n    vector<string> f, r;\n    vector<vector<int>> Xs, Ys;\n    vector<int> Xmask, Ymask;\n};\n\nstatic inline int popcnt(int x) {\n    return __builtin_popcount((unsigned)x);\n}\n\nstruct Solver {\n    int D;\n    ObjData obj[2];\n\n    Solver(int D): D(D) {}\n\n    int lin(int x, int y, int z) const {\n        return x * D * D + y * D + z;\n    }\n\n    tuple<int,int,int> invlin(int id) const {\n        int z = id % D;\n        id /= D;\n        int y = id % D;\n        int x = id / D;\n        return {x,y,z};\n    }\n\n    void prepare_obj(int idx, const vector<string>& f, const vector<string>& r) {\n        obj[idx].D = D;\n        obj[idx].f = f;\n        obj[idx].r = r;\n        obj[idx].Xs.assign(D, {});\n        obj[idx].Ys.assign(D, {});\n        obj[idx].Xmask.assign(D, 0);\n        obj[idx].Ymask.assign(D, 0);\n\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) {\n                if (f[z][x] == '1') {\n                    obj[idx].Xs[z].push_back(x);\n                    obj[idx].Xmask[z] |= (1 << x);\n                }\n            }\n            for (int y = 0; y < D; ++y) {\n                if (r[z][y] == '1') {\n                    obj[idx].Ys[z].push_back(y);\n                    obj[idx].Ymask[z] |= (1 << y);\n                }\n            }\n        }\n    }\n\n    Construction analyze_occ(const vector<char>& occ, const string& name) const {\n        Construction res;\n        res.occ = occ;\n        res.name = name;\n\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n        vector<int> occLins;\n        occLins.reserve(N);\n\n        for (int x = 0; x < D; ++x) {\n            for (int y = 0; y < D; ++y) {\n                for (int z = 0; z < D; ++z) {\n                    int id = lin(x,y,z);\n                    if (!occ[id]) continue;\n                    occLins.push_back(id);\n                    if ((x + y + z) & 1) {\n                        R_id[id] = (int)R_lin.size();\n                        R_lin.push_back(id);\n                    } else {\n                        L_id[id] = (int)L_lin.size();\n                        L_lin.push_back(id);\n                    }\n                }\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int li = 0; li < (int)L_lin.size(); ++li) {\n            auto [x,y,z] = invlin(L_lin[li]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir];\n                int ny = y + dy[dir];\n                int nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx,ny,nz);\n                if (R_id[nid] != -1) hk.add_edge(li, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n\n        vector<pair<int,int>> doms;\n        doms.reserve(L_lin.size());\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) {\n                doms.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n            }\n        }\n\n        res.occLins = move(occLins);\n        res.doms = move(doms);\n        res.V = (int)res.occLins.size();\n        return res;\n    }\n\n    vector<char> build_cross_occ(const ObjData& o, const vector<pair<int,int>>& centers) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            int cx = centers[z].first;\n            int cy = centers[z].second;\n            for (int x : o.Xs[z]) occ[lin(x, cy, z)] = 1;\n            for (int y : o.Ys[z]) occ[lin(cx, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    int cross_transition_score(const ObjData& o, int z, pair<int,int> a, pair<int,int> b) const {\n        // transition z -> z+1\n        int xcap = popcnt(o.Xmask[z] & o.Xmask[z+1]);\n        int ycap = popcnt(o.Ymask[z] & o.Ymask[z+1]);\n        int s = 0;\n        if (a.second == b.second) s += xcap;\n        if (a.first  == b.first ) s += ycap;\n        if (a.first == b.first && a.second == b.second) s -= 1;\n        return s;\n    }\n\n    vector<pair<int,int>> init_cross_centers_dp(const ObjData& o) const {\n        vector<vector<pair<int,int>>> states(D);\n        for (int z = 0; z < D; ++z) {\n            for (int x : o.Xs[z]) {\n                for (int y : o.Ys[z]) {\n                    states[z].push_back({x,y});\n                }\n            }\n        }\n\n        vector<vector<int>> dp(D), prv(D);\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1e9);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int cand = dp[z-1][i] + cross_transition_score(o, z-1, states[z-1][i], states[z][j]);\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n\n        int besti = 0;\n        for (int i = 1; i < (int)states[D-1].size(); ++i) {\n            if (dp[D-1][i] > dp[D-1][besti]) besti = i;\n        }\n\n        vector<pair<int,int>> centers(D);\n        int cur = besti;\n        for (int z = D - 1; z >= 0; --z) {\n            centers[z] = states[z][cur];\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n        return centers;\n    }\n\n    int local_overlap_score(const ObjData& o, const vector<pair<int,int>>& centers, int z, pair<int,int> cand) const {\n        int s = 0;\n        if (z > 0) s += cross_transition_score(o, z - 1, centers[z - 1], cand);\n        if (z + 1 < D) s += cross_transition_score(o, z, cand, centers[z + 1]);\n        return s;\n    }\n\n    Construction build_cross_optimized(const ObjData& o, const string& name) const {\n        vector<pair<int,int>> centers = init_cross_centers_dp(o);\n        Construction best = analyze_occ(build_cross_occ(o, centers), name + \"_init\");\n\n        bool improved = true;\n        for (int pass = 0; pass < 3 && improved; ++pass) {\n            improved = false;\n            for (int z = 0; z < D; ++z) {\n                pair<int,int> curCenter = centers[z];\n                int curMatch = (int)best.doms.size();\n                int curTie = local_overlap_score(o, centers, z, curCenter);\n\n                pair<int,int> bestCenter = curCenter;\n                Construction bestCand = best;\n                int bestMatch = curMatch;\n                int bestTie = curTie;\n\n                for (int x : o.Xs[z]) {\n                    for (int y : o.Ys[z]) {\n                        pair<int,int> cand = {x,y};\n                        if (cand == curCenter) continue;\n                        centers[z] = cand;\n                        auto occ = build_cross_occ(o, centers);\n                        Construction c = analyze_occ(occ, name);\n                        int m = (int)c.doms.size();\n                        int tie = local_overlap_score(o, centers, z, cand);\n                        if (m > bestMatch || (m == bestMatch && tie > bestTie)) {\n                            bestMatch = m;\n                            bestTie = tie;\n                            bestCenter = cand;\n                            bestCand = move(c);\n                        }\n                    }\n                }\n\n                centers[z] = bestCenter;\n                if (bestCenter != curCenter) {\n                    best = move(bestCand);\n                    if (bestMatch > curMatch) improved = true;\n                }\n            }\n        }\n\n        best.name = name;\n        return best;\n    }\n\n    vector<char> build_min_occ(const ObjData& o, bool rev) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            auto X = o.Xs[z];\n            auto Y = o.Ys[z];\n            int a = (int)X.size();\n            int b = (int)Y.size();\n\n            if (a >= b) {\n                if (rev) reverse(Y.begin(), Y.end());\n                for (int j = 0; j < b; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = b; j < a; ++j) occ[lin(X[j], Y[0], z)] = 1;\n            } else {\n                if (rev) reverse(X.begin(), X.end());\n                for (int j = 0; j < a; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = a; j < b; ++j) occ[lin(X[0], Y[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    double eval_pair(const Construction& a, const Construction& b) const {\n        int sd = min((int)a.doms.size(), (int)b.doms.size());\n        int remA = a.V - 2 * sd;\n        int remB = b.V - 2 * sd;\n        return max(remA, remB) + 0.5 * sd;\n    }\n\n    pair<vector<int>, vector<int>> build_output_arrays(const Construction& A, const Construction& B) const {\n        int sd = min((int)A.doms.size(), (int)B.doms.size());\n\n        vector<char> usedA(D * D * D, 0), usedB(D * D * D, 0);\n        vector<int> outA(D * D * D, 0), outB(D * D * D, 0);\n\n        int id = 1;\n        for (int i = 0; i < sd; ++i) {\n            auto [a1, a2] = A.doms[i];\n            auto [b1, b2] = B.doms[i];\n            usedA[a1] = usedA[a2] = 1;\n            usedB[b1] = usedB[b2] = 1;\n            outA[a1] = outA[a2] = id;\n            outB[b1] = outB[b2] = id;\n            ++id;\n        }\n\n        vector<int> leftA, leftB;\n        leftA.reserve(A.V);\n        leftB.reserve(B.V);\n        for (int v : A.occLins) if (!usedA[v]) leftA.push_back(v);\n        for (int v : B.occLins) if (!usedB[v]) leftB.push_back(v);\n\n        int su = min((int)leftA.size(), (int)leftB.size());\n        for (int i = 0; i < su; ++i) {\n            outA[leftA[i]] = id;\n            outB[leftB[i]] = id;\n            ++id;\n        }\n        for (int i = su; i < (int)leftA.size(); ++i) {\n            outA[leftA[i]] = id++;\n        }\n        for (int i = su; i < (int)leftB.size(); ++i) {\n            outB[leftB[i]] = id++;\n        }\n\n        return {outA, outB};\n    }\n\n    void solve_and_print() {\n        vector<Construction> cand1, cand2;\n\n        cand1.push_back(build_cross_optimized(obj[0], \"cross\"));\n        cand1.push_back(analyze_occ(build_min_occ(obj[0], false), \"minA\"));\n        cand1.push_back(analyze_occ(build_min_occ(obj[0], true),  \"minB\"));\n\n        cand2.push_back(build_cross_optimized(obj[1], \"cross\"));\n        cand2.push_back(analyze_occ(build_min_occ(obj[1], false), \"minA\"));\n        cand2.push_back(analyze_occ(build_min_occ(obj[1], true),  \"minB\"));\n\n        int bi = 0, bj = 0;\n        double bestScore = 1e100;\n        for (int i = 0; i < (int)cand1.size(); ++i) {\n            for (int j = 0; j < (int)cand2.size(); ++j) {\n                double sc = eval_pair(cand1[i], cand2[j]);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        auto [out1, out2] = build_output_arrays(cand1[bi], cand2[bj]);\n\n        int n = 0;\n        for (int v : out1) n = max(n, v);\n        for (int v : out2) n = max(n, v);\n\n        cout << n << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out1[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out2[i];\n        }\n        cout << '\\n';\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> f1(D), r1(D), f2(D), r2(D);\n    for (int i = 0; i < D; ++i) cin >> f1[i];\n    for (int i = 0; i < D; ++i) cin >> r1[i];\n    for (int i = 0; i < D; ++i) cin >> f2[i];\n    for (int i = 0; i < D; ++i) cin >> r2[i];\n\n    Solver solver(D);\n    solver.prepare_obj(0, f1, r1);\n    solver.prepare_obj(1, f2, r2);\n    solver.solve_and_print();\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }\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;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Tree {\n    vector<char> edgeOn;\n    vector<char> vertexOn;\n};\n\nstruct Solution {\n    vector<int> P;\n    vector<char> B;\n    long long S = (1LL << 62);\n    bool feasible = false;\n};\n\nstatic const long long INF64 = (1LL << 60);\n\nint N, M, K;\nvector<int> X, Y;\nvector<Edge> edges;\nvector<int> A, Bp;\nvector<vector<pair<int,int>>> g; // (to, edge_id)\n\nvector<vector<long long>> distSP;\nvector<vector<int>> parentV, parentE;\n\n// reqPow[v][k] = minimum integer power needed for vertex v to cover resident k.\n// 5001 means impossible due to P<=5000.\nvector<vector<unsigned short>> reqPow;\n\n// coverList[v] = sorted list of (required_power, resident_id), only for required_power <= 5000.\nvector<vector<pair<int,int>>> coverList;\n\nint ceil_sqrt_ll(long long x) {\n    long long r = 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\nvoid compute_all_pairs_shortest_paths() {\n    distSP.assign(N, vector<long long>(N, INF64));\n    parentV.assign(N, vector<int>(N, -1));\n    parentE.assign(N, vector<int>(N, -1));\n\n    for (int s = 0; s < N; ++s) {\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        distSP[s][s] = 0;\n        parentV[s][s] = s;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != distSP[s][v]) continue;\n\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < distSP[s][to]) {\n                    distSP[s][to] = nd;\n                    parentV[s][to] = v;\n                    parentE[s][to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n}\n\nvoid preprocess_cover_info() {\n    reqPow.assign(N, vector<unsigned short>(K, 5001));\n    coverList.assign(N, {});\n\n    for (int v = 0; v < N; ++v) {\n        coverList[v].reserve(K);\n        for (int k = 0; k < K; ++k) {\n            long long dx = 1LL * X[v] - A[k];\n            long long dy = 1LL * Y[v] - Bp[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            if (p <= 5000) {\n                reqPow[v][k] = (unsigned short)p;\n                coverList[v].push_back({p, k});\n            }\n        }\n        sort(coverList[v].begin(), coverList[v].end());\n    }\n}\n\nvoid add_path_from_source(int s, int t, vector<char>& inTree, vector<char>& edgeOn, vector<int>& newVertices) {\n    int cur = t;\n    while (cur != s) {\n        int pe = parentE[s][cur];\n        int pv = parentV[s][cur];\n        if (pe < 0 || pv < 0) break; // safety\n        if (!edgeOn[pe]) edgeOn[pe] = 1;\n        if (!inTree[cur]) {\n            inTree[cur] = 1;\n            newVertices.push_back(cur);\n        }\n        if (!inTree[pv]) {\n            inTree[pv] = 1;\n            newVertices.push_back(pv);\n        }\n        cur = pv;\n    }\n}\n\nlong long calc_cost(const vector<int>& P, const vector<char>& Eon) {\n    long long s = 0;\n    for (int i = 0; i < N; ++i) s += 1LL * P[i] * P[i];\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nbool verify_solution(const vector<int>& P, const vector<char>& Eon) {\n    vector<char> vis(N, 0);\n    queue<int> q;\n    vis[0] = 1;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (auto [to, eid] : g[v]) {\n            if (!Eon[eid]) continue;\n            if (!vis[to]) {\n                vis[to] = 1;\n                q.push(to);\n            }\n        }\n    }\n\n    for (int k = 0; k < K; ++k) {\n        bool ok = false;\n        for (int v = 0; v < N; ++v) {\n            if (!vis[v]) continue;\n            if (P[v] > 0 && reqPow[v][k] <= P[v]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nTree build_tree_from_terminals(const vector<int>& P) {\n    vector<int> terminals;\n    vector<char> isTerminal(N, 0);\n    terminals.push_back(0);\n    isTerminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminals.push_back(i);\n            isTerminal[i] = 1;\n        }\n    }\n\n    vector<char> unionOn(M, 0);\n\n    if ((int)terminals.size() >= 2) {\n        int T = terminals.size();\n\n        // MST on metric closure by Prim\n        vector<long long> best(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> used(T, 0);\n        best[0] = 0;\n\n        for (int it = 0; it < T; ++it) {\n            int v = -1;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                int s = terminals[par[v]];\n                int t = terminals[v];\n                int cur = t;\n                while (cur != s) {\n                    int pe = parentE[s][cur];\n                    int pv = parentV[s][cur];\n                    if (pe < 0 || pv < 0) break;\n                    unionOn[pe] = 1;\n                    cur = pv;\n                }\n            }\n\n            for (int to = 0; to < T; ++to) {\n                if (used[to]) continue;\n                long long d = distSP[terminals[v]][terminals[to]];\n                if (d < best[to]) {\n                    best[to] = d;\n                    par[to] = v;\n                }\n            }\n        }\n    }\n\n    // Kruskal on the union edges\n    vector<int> ids;\n    ids.reserve(M);\n    for (int e = 0; e < M; ++e) if (unionOn[e]) ids.push_back(e);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return edges[a].w < edges[b].w;\n    });\n\n    vector<char> sel(M, 0);\n    DSU dsu(N);\n    for (int e : ids) {\n        if (dsu.merge(edges[e].u, edges[e].v)) sel[e] = 1;\n    }\n\n    // Prune non-terminal leaves\n    vector<vector<int>> inc(N);\n    vector<int> deg(N, 0);\n    for (int e = 0; e < M; ++e) {\n        if (!sel[e]) continue;\n        int u = edges[e].u, v = edges[e].v;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n        deg[u]++;\n        deg[v]++;\n    }\n\n    vector<char> removed(M, 0);\n    queue<int> q;\n    for (int v = 0; v < N; ++v) {\n        if (!isTerminal[v] && deg[v] == 1) q.push(v);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (isTerminal[v] || deg[v] != 1) continue;\n\n        int remE = -1;\n        for (int e : inc[v]) {\n            if (sel[e] && !removed[e]) {\n                remE = e;\n                break;\n            }\n        }\n        if (remE == -1) continue;\n\n        removed[remE] = 1;\n        deg[v]--;\n\n        int to = edges[remE].u ^ edges[remE].v ^ v;\n        deg[to]--;\n        if (!isTerminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    Tree tr;\n    tr.edgeOn.assign(M, 0);\n    tr.vertexOn.assign(N, 0);\n    tr.vertexOn[0] = 1;\n    for (int i = 0; i < N; ++i) if (isTerminal[i]) tr.vertexOn[i] = 1;\n\n    for (int e = 0; e < M; ++e) {\n        if (sel[e] && !removed[e]) {\n            tr.edgeOn[e] = 1;\n            tr.vertexOn[edges[e].u] = 1;\n            tr.vertexOn[edges[e].v] = 1;\n        }\n    }\n    return tr;\n}\n\nvoid shrink_exclusive(vector<int>& P, const vector<int>& allowed) {\n    while (true) {\n        vector<int> cnt(K, 0);\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= pv) cnt[k]++;\n            }\n        }\n\n        bool changed = false;\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int oldP = P[v];\n            int need = 0;\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= oldP && cnt[k] == 1) {\n                    need = max(need, (int)reqPow[v][k]);\n                }\n            }\n            if (need < oldP) {\n                for (int k = 0; k < K; ++k) {\n                    if (reqPow[v][k] <= oldP && reqPow[v][k] > need) {\n                        cnt[k]--;\n                    }\n                }\n                P[v] = need;\n                changed = true;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvector<int> greedy_cover_fixed_tree(const vector<int>& allowed) {\n    vector<int> P(N, 0);\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : allowed) {\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            // Safety fallback\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : allowed) {\n                    int rp = reqPow[v][k];\n                    if (rp <= 5000 && rp > P[v]) {\n                        bestV = v;\n                        bestP = rp;\n                        break;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    shrink_exclusive(P, allowed);\n    return P;\n}\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> treeVertex;\n    vector<char> treeEdge;\n};\n\nInitialState initial_connected_greedy(double connFactor) {\n    vector<int> P(N, 0);\n    vector<char> inTree(N, 0), edgeOn(M, 0);\n    inTree[0] = 1;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n    for (int i = 0; i < N; ++i) bestFrom[i] = 0;\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v = 0; v < N; ++v) {\n            long double conn = inTree[v] ? 0.0L : (long double)connFactor * bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            // Safety fallback: cover one uncovered resident as cheaply as possible\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K; ++k) if (!covered[k]) {\n                for (int v = 0; v < N; ++v) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inTree[v] ? 0.0L : (long double)connFactor * bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n                if (bestV != -1) break;\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inTree[bestV]) {\n            vector<int> newVertices;\n            add_path_from_source(bestFrom[bestV], bestV, inTree, edgeOn, newVertices);\n            if (newVertices.empty()) {\n                inTree[bestV] = 1;\n                newVertices.push_back(bestV);\n            }\n            for (int nv : newVertices) {\n                for (int t = 0; t < N; ++t) {\n                    if (distSP[nv][t] < bestDist[t]) {\n                        bestDist[t] = distSP[nv][t];\n                        bestFrom[t] = nv;\n                    }\n                }\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    return {P, inTree, edgeOn};\n}\n\nSolution solve_attempt(double connFactor) {\n    Solution sol;\n\n    InitialState init = initial_connected_greedy(connFactor);\n\n    vector<int> P = init.P;\n    vector<int> allowed;\n    for (int i = 0; i < N; ++i) if (init.treeVertex[i]) allowed.push_back(i);\n\n    // Optimize cover on initial connected vertex set\n    P = greedy_cover_fixed_tree(allowed);\n\n    for (int it = 0; it < 2; ++it) {\n        Tree tr = build_tree_from_terminals(P);\n        allowed.clear();\n        for (int i = 0; i < N; ++i) if (tr.vertexOn[i]) allowed.push_back(i);\n        P = greedy_cover_fixed_tree(allowed);\n    }\n\n    Tree finalTree = build_tree_from_terminals(P);\n\n    // One last cover optimization on final tree\n    allowed.clear();\n    for (int i = 0; i < N; ++i) if (finalTree.vertexOn[i]) allowed.push_back(i);\n    P = greedy_cover_fixed_tree(allowed);\n    finalTree = build_tree_from_terminals(P);\n\n    sol.P = P;\n    sol.B = finalTree.edgeOn;\n    sol.S = calc_cost(sol.P, sol.B);\n    sol.feasible = verify_solution(sol.P, sol.B);\n    if (!sol.feasible) sol.S = (1LL << 62);\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; ++i) cin >> X[i] >> Y[i];\n\n    edges.resize(M);\n    g.assign(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, v, w};\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    A.resize(K);\n    Bp.resize(K);\n    for (int i = 0; i < K; ++i) cin >> A[i] >> Bp[i];\n\n    compute_all_pairs_shortest_paths();\n    preprocess_cover_info();\n\n    vector<double> factors = {0.7, 1.0, 1.4};\n    Solution best;\n\n    for (double f : factors) {\n        Solution cur = solve_attempt(f);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    // Safety fallback: if something went wrong, use the middle factor result.\n    if (!best.feasible) {\n        best = solve_attempt(1.0);\n    }\n    if (!best.feasible) {\n        // Extremely conservative fallback:\n        // connect all vertices by shortest-path-tree from root, and cover greedily on all vertices.\n        vector<int> P = greedy_cover_fixed_tree([&]{\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            return all;\n        }());\n        Tree tr = build_tree_from_terminals(P);\n        best.P = P;\n        best.B = tr.edgeOn;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (int)best.B[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nusing Board = array<array<int, N>, N>;\n\nstruct SimResult {\n    Board b;\n    vector<Op> ops;\n};\n\nstatic inline void move_min_to_root(Board& b, vector<Op>& ops, int x, int y) {\n    int bestVal = INT_MAX;\n    int bi = -1, bj = -1;\n\n    // Find the minimum inside the descendant triangle rooted at (x, y).\n    for (int i = x; i < N; ++i) {\n        for (int j = y; j <= y + (i - x); ++j) {\n            if (b[i][j] < bestVal) {\n                bestVal = b[i][j];\n                bi = i;\n                bj = j;\n            }\n        }\n    }\n\n    int i = bi, j = bj;\n\n    // Move it upward along a shortest path.\n    // If both upward parents are possible, choose the larger one to push down.\n    while (i > x) {\n        int d = i - x;\n        int k = j - y;  // relative horizontal offset inside the triangle\n\n        bool canLeftUp = (k > 0);   // to (i-1, j-1)\n        bool canUp     = (k < d);   // to (i-1, j)\n\n        int ni, nj;\n        if (canLeftUp && !canUp) {\n            ni = i - 1;\n            nj = j - 1;\n        } else if (!canLeftUp && canUp) {\n            ni = i - 1;\n            nj = j;\n        } else {\n            // Both are possible: push the larger parent downward.\n            if (b[i - 1][j - 1] > b[i - 1][j]) {\n                ni = i - 1;\n                nj = j - 1;\n            } else {\n                ni = i - 1;\n                nj = j;\n            }\n        }\n\n        swap(b[i][j], b[ni][nj]);\n        ops.push_back({i, j, ni, nj});\n        i = ni;\n        j = nj;\n    }\n}\n\nstatic SimResult simulate_row(const Board& src, int x, bool left_to_right) {\n    SimResult res;\n    res.b = src;\n\n    if (left_to_right) {\n        for (int y = 0; y <= x; ++y) {\n            move_min_to_root(res.b, res.ops, x, y);\n        }\n    } else {\n        for (int y = x; y >= 0; --y) {\n            move_min_to_root(res.b, res.ops, x, y);\n        }\n    }\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board board{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> board[x][y];\n        }\n    }\n\n    vector<Op> answer;\n    answer.reserve(5000);\n\n    for (int x = 0; x < N; ++x) {\n        // Try both directions for this row and keep the cheaper one.\n        SimResult lr = simulate_row(board, x, true);\n        SimResult rl = simulate_row(board, x, false);\n\n        if (lr.ops.size() <= rl.ops.size()) {\n            board = lr.b;\n            for (auto &op : lr.ops) answer.push_back(op);\n        } else {\n            board = rl.b;\n            for (auto &op : rl.ops) answer.push_back(op);\n        }\n    }\n\n    // Guaranteed <= 4495 with this construction.\n    cout << answer.size() << '\\n';\n    for (auto &op : answer) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int D, N, M, mid, entrance;\n    array<char, 81> obstacle{};\n    array<char, 81> occupied{};\n    vector<vector<int>> nbrs;\n    vector<int> free_ids;\n    vector<int> label_at;\n    vector<char> used;\n    int current_empty_count; // includes entrance\n\n    Solver(int D_, int N_) : D(D_), N(N_) {\n        mid = (D - 1) / 2;\n        entrance = mid; // (0, mid)\n        nbrs.assign(D * D, {});\n        label_at.assign(D * D, -1);\n        build_neighbors();\n    }\n\n    inline int id(int i, int j) const { return i * D + j; }\n    inline int row(int v) const { return v / D; }\n    inline int col(int v) const { return v % D; }\n\n    void build_neighbors() {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int v = id(i, j);\n                if (i > 0) nbrs[v].push_back(id(i - 1, j));\n                if (i + 1 < D) nbrs[v].push_back(id(i + 1, j));\n                if (j > 0) nbrs[v].push_back(id(i, j - 1));\n                if (j + 1 < D) nbrs[v].push_back(id(i, j + 1));\n            }\n        }\n    }\n\n    void finalize_init() {\n        free_ids.clear();\n        for (int i = 0; i < D * D; ++i) {\n            if (i == entrance) continue;\n            if (obstacle[i]) continue;\n            free_ids.push_back(i);\n        }\n        M = (int)free_ids.size();\n        used.assign(M, 0);\n        current_empty_count = M + 1; // all free cells + entrance\n    }\n\n    bool connected_after_occupy(const array<char, 81>& occ, int empty_count, int ban) const {\n        // Check whether passable cells (entrance + empty cells except ban) stay connected.\n        array<char, 81> vis{};\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n        int cnt = 1;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (vis[to]) continue;\n                if (to == ban) continue;\n                if (obstacle[to]) continue;\n                if (occ[to]) continue;\n                vis[to] = 1;\n                q[qt++] = to;\n                ++cnt;\n            }\n        }\n        return cnt == empty_count - 1;\n    }\n\n    vector<int> legal_cells(const array<char, 81>& occ, int empty_count) const {\n        vector<int> res;\n        res.reserve(empty_count);\n        for (int v : free_ids) {\n            if (occ[v]) continue;\n            if (connected_after_occupy(occ, empty_count, v)) res.push_back(v);\n        }\n        return res;\n    }\n\n    vector<int> bfs_dist_empty(const array<char, 81>& occ) const {\n        vector<int> dist(D * D, -1);\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        dist[entrance] = 0;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (dist[to] != -1) continue;\n                if (obstacle[to]) continue;\n                if (occ[to]) continue;\n                dist[to] = dist[v] + 1;\n                q[qt++] = to;\n            }\n        }\n        return dist;\n    }\n\n    int current_degree_empty(int v, const array<char, 81>& occ) const {\n        int deg = 0;\n        for (int to : nbrs[v]) {\n            if (obstacle[to]) continue;\n            if (occ[to]) continue;\n            ++deg;\n        }\n        return deg;\n    }\n\n    vector<int> dynamic_estimated_output_rank() const {\n        // Estimate future output order for remaining empty cells:\n        // peel legal cells from far away to near core; reverse peel = estimated output order.\n        array<char, 81> temp_occ = occupied;\n        int empty_count = current_empty_count;\n        int rem = empty_count - 1; // excluding entrance\n\n        vector<int> est_rank(D * D, -1);\n\n        for (int step = 0; step < rem; ++step) {\n            auto dist = bfs_dist_empty(temp_occ);\n            auto legal = legal_cells(temp_occ, empty_count);\n\n            int best = -1;\n            int bestDist = -1;\n            int bestDeg = 100;\n            int bestMan = -1;\n\n            for (int v : legal) {\n                int dv = dist[v];\n                int deg = current_degree_empty(v, temp_occ);\n                int man = row(v) + abs(col(v) - mid);\n\n                if (best == -1 ||\n                    dv > bestDist ||\n                    (dv == bestDist && deg < bestDeg) ||\n                    (dv == bestDist && deg == bestDeg && man > bestMan) ||\n                    (dv == bestDist && deg == bestDeg && man == bestMan && v < best)) {\n                    best = v;\n                    bestDist = dv;\n                    bestDeg = deg;\n                    bestMan = man;\n                }\n            }\n\n            est_rank[best] = rem - 1 - step; // 0 = early estimated output, larger = later\n            temp_occ[best] = 1;\n            --empty_count;\n        }\n        return est_rank;\n    }\n\n    int rank_among_remaining_labels(int t) const {\n        int r = 0;\n        for (int x = 0; x < t; ++x) {\n            if (!used[x]) ++r;\n        }\n        return r;\n    }\n\n    int choose_place(int t) const {\n        auto est_rank = dynamic_estimated_output_rank();\n        auto legal = legal_cells(occupied, current_empty_count);\n        int r = rank_among_remaining_labels(t);\n\n        int best = -1;\n        tuple<long long, int, int, int, int> best_key;\n\n        for (int v : legal) {\n            long long diff = llabs((long long)est_rank[v] - r);\n            int later_penalty = (est_rank[v] > r) ? 1 : 0; // prefer slightly earlier slots on tie\n            int man = row(v) + abs(col(v) - mid);\n            auto key = make_tuple(diff, later_penalty, est_rank[v], -man, v);\n            if (best == -1 || key < best_key) {\n                best = v;\n                best_key = key;\n            }\n        }\n        return best;\n    }\n\n    int choose_remove() const {\n        array<char, 81> vis{};\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n\n        int best = -1;\n        array<char, 81> added{};\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (obstacle[to]) continue;\n                if (occupied[to]) {\n                    if (!added[to]) {\n                        added[to] = 1;\n                        if (best == -1 || label_at[to] < label_at[best]) best = to;\n                    }\n                } else {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[qt++] = to;\n                    }\n                }\n            }\n        }\n        return best;\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    Solver solver(D, N);\n\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        solver.obstacle[solver.id(r, c)] = 1;\n    }\n    solver.finalize_init();\n\n    for (int d = 0; d < solver.M; ++d) {\n        int t;\n        cin >> t;\n\n        int v = solver.choose_place(t);\n\n        solver.occupied[v] = 1;\n        solver.label_at[v] = t;\n        solver.used[t] = 1;\n        --solver.current_empty_count;\n\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n' << flush;\n    }\n\n    for (int k = 0; k < solver.M; ++k) {\n        int v = solver.choose_remove();\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n';\n        solver.occupied[v] = 0;\n    }\n    cout << flush;\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXC = 100;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nstruct DeltaPack {\n    int u[16], v[16], d[16];\n    int sz = 0;\n\n    void clear() { sz = 0; }\n\n    void add(int a, int b, int val) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < sz; i++) {\n            if (u[i] == a && v[i] == b) {\n                d[i] += val;\n                return;\n            }\n        }\n        u[sz] = a;\n        v[sz] = b;\n        d[sz] = val;\n        sz++;\n    }\n};\n\nstruct Solver {\n    int n, m;\n    int orig[MAXN][MAXN];\n    bool target[MAXC + 1][MAXC + 1]{};\n\n    int g[MAXN][MAXN];\n    int bestg[MAXN][MAXN];\n\n    int area[MAXC + 1]{};\n    int adjcnt[MAXC + 1][MAXC + 1]{};\n\n    int bestZero = -1;\n\n    mt19937 rng;\n\n    Solver() {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < n && 0 <= y && y < n;\n    }\n\n    void build_adj_from_board(int board[MAXN][MAXN], int cnt[MAXC + 1][MAXC + 1]) {\n        for (int i = 0; i <= m; i++) for (int j = 0; j <= m; j++) cnt[i][j] = 0;\n\n        auto add_pair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            cnt[a][b]++;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int c = board[i][j];\n                if (i == 0) add_pair(c, 0);\n                if (j == 0) add_pair(c, 0);\n                if (i + 1 < n) add_pair(c, board[i + 1][j]);\n                else add_pair(c, 0);\n                if (j + 1 < n) add_pair(c, board[i][j + 1]);\n                else add_pair(c, 0);\n            }\n        }\n    }\n\n    void init_target() {\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(orig, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = 0; j <= m; j++) target[i][j] = false;\n        }\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                target[i][j] = target[j][i] = (cnt[i][j] > 0);\n            }\n        }\n    }\n\n    void reset_state() {\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) g[i][j] = orig[i][j];\n        for (int c = 0; c <= m; c++) area[c] = 0;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) area[g[i][j]]++;\n        build_adj_from_board(g, adjcnt);\n    }\n\n    bool can_remove_color_cell(int x, int y) {\n        int c = g[x][y];\n        if (c == 0) return false;\n        if (area[c] <= 1) return false;\n\n        pair<int,int> same[4];\n        int k = 0;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (inside(nx, ny) && g[nx][ny] == c) same[k++] = {nx, ny};\n        }\n\n        if (k == 0) return false; // impossible unless area[c]==1, but safe\n        if (k == 1) return true;  // removing a leaf cannot disconnect\n\n        static int vis[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        q.push(same[0]);\n        vis[same[0].first][same[0].second] = stamp;\n        int cnt = 0;\n\n        while (!q.empty()) {\n            auto [cx, cy] = q.front();\n            q.pop();\n            cnt++;\n            if (cnt == area[c] - 1) return true;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = cx + dx[dir], ny = cy + dy[dir];\n                if (!inside(nx, ny)) continue;\n                if (nx == x && ny == y) continue;\n                if (g[nx][ny] != c) continue;\n                if (vis[nx][ny] == stamp) continue;\n                vis[nx][ny] = stamp;\n                q.push({nx, ny});\n            }\n        }\n\n        return cnt == area[c] - 1;\n    }\n\n    bool can_attach_zero(int x, int y) const {\n        if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return true;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (inside(nx, ny) && g[nx][ny] == 0) return true;\n        }\n        return false;\n    }\n\n    bool check_move(int x, int y, int t, int &deltaPerim, DeltaPack &pack) {\n        int c = g[x][y];\n        if (c == t) return false;\n        if (c == 0) return false;\n\n        if (t == 0) {\n            if (!can_attach_zero(x, y)) return false;\n        } else {\n            bool touch = false;\n            static const int dx[4] = {-1, 1, 0, 0};\n            static const int dy[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (inside(nx, ny) && g[nx][ny] == t) touch = true;\n            }\n            if (!touch) return false;\n        }\n\n        pack.clear();\n        deltaPerim = 0;\n\n        auto process_side = [&](int other) {\n            deltaPerim += (t != other) - (c != other);\n            pack.add(c, other, -1);\n            pack.add(t, other, +1);\n        };\n\n        if (x > 0) process_side(g[x - 1][y]);\n        else process_side(0);\n        if (x + 1 < n) process_side(g[x + 1][y]);\n        else process_side(0);\n        if (y > 0) process_side(g[x][y - 1]);\n        else process_side(0);\n        if (y + 1 < n) process_side(g[x][y + 1]);\n        else process_side(0);\n\n        for (int i = 0; i < pack.sz; i++) {\n            int a = pack.u[i], b = pack.v[i];\n            int after = adjcnt[a][b] + pack.d[i];\n            if ((after > 0) != target[a][b]) return false;\n        }\n        return true;\n    }\n\n    void apply_move(int x, int y, int t, const DeltaPack &pack) {\n        int c = g[x][y];\n        area[c]--;\n        area[t]++;\n        g[x][y] = t;\n        for (int i = 0; i < pack.sz; i++) {\n            adjcnt[pack.u[i]][pack.v[i]] += pack.d[i];\n        }\n    }\n\n    void local_search(double time_limit_sec, const Timer &timer) {\n        reset_state();\n\n        vector<int> ord(n * n);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int phase = 0; phase < 2; phase++) {\n            while (timer.elapsed() < time_limit_sec) {\n                bool improved = false;\n                shuffle(ord.begin(), ord.end(), rng);\n\n                for (int id : ord) {\n                    if (timer.elapsed() >= time_limit_sec) break;\n\n                    int x = id / n, y = id % n;\n                    int c = g[x][y];\n                    if (c == 0) continue;\n\n                    if (!can_remove_color_cell(x, y)) continue;\n\n                    // In phase 1, prioritize deletion to zero.\n                    if (phase == 1) {\n                        int dp;\n                        DeltaPack pack;\n                        if (check_move(x, y, 0, dp, pack)) {\n                            apply_move(x, y, 0, pack);\n                            improved = true;\n                            continue;\n                        }\n                    }\n\n                    bool used[MAXC + 1] = {};\n                    vector<int> cand;\n                    cand.reserve(4);\n\n                    static const int dx[4] = {-1, 1, 0, 0};\n                    static const int dy[4] = {0, 0, -1, 1};\n                    for (int dir = 0; dir < 4; dir++) {\n                        int nx = x + dx[dir], ny = y + dy[dir];\n                        if (!inside(nx, ny)) continue;\n                        int t = g[nx][ny];\n                        if (t > 0 && t != c && !used[t]) {\n                            used[t] = true;\n                            cand.push_back(t);\n                        }\n                    }\n\n                    shuffle(cand.begin(), cand.end(), rng);\n\n                    int bestT = -1;\n                    int bestDP = 0;\n                    DeltaPack bestPack;\n\n                    for (int t : cand) {\n                        int dp;\n                        DeltaPack pack;\n                        if (!check_move(x, y, t, dp, pack)) continue;\n                        if (dp < bestDP) {\n                            bestDP = dp;\n                            bestT = t;\n                            bestPack = pack;\n                        }\n                    }\n\n                    if (bestT != -1) {\n                        apply_move(x, y, bestT, bestPack);\n                        improved = true;\n                    }\n                }\n\n                if (!improved) break;\n            }\n        }\n\n        if (area[0] > bestZero) {\n            bestZero = area[0];\n            for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = g[i][j];\n        }\n    }\n\n    bool full_validate(int board[MAXN][MAXN]) {\n        int cntArea[MAXC + 1] = {};\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cntArea[board[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cntArea[c] == 0) return false;\n\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(board, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                bool cur = cnt[i][j] > 0;\n                if (cur != target[i][j]) return false;\n            }\n        }\n\n        static int vis[MAXN][MAXN];\n        memset(vis, 0, sizeof(vis));\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // Positive colors connectivity\n        for (int c = 1; c <= m; c++) {\n            pair<int,int> st = {-1, -1};\n            for (int i = 0; i < n && st.first == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (board[i][j] == c) {\n                        st = {i, j};\n                        break;\n                    }\n                }\n            }\n            if (st.first == -1) return false;\n\n            queue<pair<int,int>> q;\n            q.push(st);\n            vis[st.first][st.second] = c + 1000;\n            int got = 0;\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != c) continue;\n                    if (vis[nx][ny] == c + 1000) continue;\n                    vis[nx][ny] = c + 1000;\n                    q.push({nx, ny});\n                }\n            }\n\n            if (got != cntArea[c]) return false;\n        }\n\n        // Zero connectivity through outside:\n        if (cntArea[0] > 0) {\n            vector<vector<int>> zvis(n, vector<int>(n, 0));\n            queue<pair<int,int>> q;\n            int got = 0;\n            for (int i = 0; i < n; i++) {\n                for (int j : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n            for (int j = 0; j < n; j++) {\n                for (int i : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != 0 || zvis[nx][ny]) continue;\n                    zvis[nx][ny] = 1;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[0]) return false;\n        }\n\n        return true;\n    }\n\n    void solve() {\n        cin >> n >> m;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) cin >> orig[i][j];\n        }\n\n        init_target();\n\n        Timer timer;\n        const double TL = 1.92;\n\n        bestZero = -1;\n\n        while (timer.elapsed() < TL) {\n            local_search(TL, timer);\n        }\n\n        if (!full_validate(bestg)) {\n            // Fallback to original if something went wrong.\n            for (int i = 0; i < n; i++) {\n                for (int j = 0; j < n; j++) {\n                    cout << orig[i][j] << (j + 1 == n ? '\\n' : ' ');\n                }\n            }\n            return;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                cout << bestg[i][j] << (j + 1 == n ? '\\n' : ' ');\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Bin {\n    vector<int> items;\n    long double est_load = 0;\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int lgD = 0;\n\n    vector<int> insc;                  // insertion-sort exact cost for prefix size k\n    vector<long double> H;             // harmonic numbers\n    vector<long double> est_by_pos;    // estimated weight by rank position\n    vector<long double> est_by_item;   // estimated weight by item after final order chosen\n\n    static int ceil_log2_int(int x) {\n        int k = 0, p = 1;\n        while (p < x) p <<= 1, ++k;\n        return k;\n    }\n\n    int ask(const vector<int>& L, const vector<int>& R) {\n        // Must be non-empty and disjoint.\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        cin >> s;\n        ++used;\n        if (s == \"<\") return -1;\n        if (s == \">\") return 1;\n        return 0;\n    }\n\n    int cmp_item(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask(L, R);\n    }\n\n    vector<int> exact_sort_items(const vector<int>& items) {\n        // Descending order: heavier first.\n        vector<int> sorted;\n        sorted.reserve(items.size());\n        for (int x : items) {\n            int l = 0, r = (int)sorted.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = cmp_item(x, sorted[m]);\n                if (c > 0) r = m;      // x heavier -> go left\n                else l = m + 1;        // x <= sorted[m] -> go right\n            }\n            sorted.insert(sorted.begin() + l, x);\n        }\n        return sorted;\n    }\n\n    vector<int> tournament_order() {\n        vector<int> depth(N, 0);\n        vector<int> cur(N);\n        iota(cur.begin(), cur.end(), 0);\n\n        int round = 0;\n        while ((int)cur.size() > 1) {\n            vector<int> nxt;\n            nxt.reserve((cur.size() + 1) / 2);\n            for (int i = 0; i + 1 < (int)cur.size(); i += 2) {\n                int a = cur[i], b = cur[i + 1];\n                int c = cmp_item(a, b);\n                int winner, loser;\n                if (c >= 0) {\n                    winner = a;\n                    loser = b;\n                } else {\n                    winner = b;\n                    loser = a;\n                }\n                depth[loser] = round;\n                nxt.push_back(winner);\n            }\n            if ((int)cur.size() & 1) nxt.push_back(cur.back());\n            cur.swap(nxt);\n            ++round;\n        }\n        depth[cur[0]] = round;\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (depth[a] != depth[b]) return depth[a] > depth[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<Bin> estimated_assign_all(const vector<int>& order, int fixed_prefix = 0) {\n        vector<Bin> bins(D);\n        for (int p = 0; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_by_item[item];\n        }\n        return bins;\n    }\n\n    vector<Bin> hybrid_assign(const vector<int>& order, int K) {\n        // First K items are handled with exact order.\n        // Top D initialize bins; next K-D items are assigned to actual lightest bin\n        // using real bin-sum comparisons; the rest are assigned by estimated weights.\n        if (K < D) {\n            return estimated_assign_all(order);\n        }\n\n        vector<Bin> bins(D);\n\n        // order is exact descending at least for [0, K)\n        // So actual ascending among first D is reverse order.\n        for (int j = 0; j < D; ++j) {\n            int item = order[D - 1 - j];\n            bins[j].items.push_back(item);\n            bins[j].est_load += est_by_item[item];\n        }\n\n        for (int p = D; p < K; ++p) {\n            Bin cur = std::move(bins[0]);\n            bins.erase(bins.begin());\n\n            int item = order[p];\n            cur.items.push_back(item);\n            cur.est_load += est_by_item[item];\n\n            int l = 0, r = (int)bins.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = ask(cur.items, bins[m].items); // compare actual sums\n                if (c <= 0) r = m; // cur <= bins[m] => go left\n                else l = m + 1;\n            }\n            bins.insert(bins.begin() + l, std::move(cur));\n        }\n\n        // Remaining items: estimated greedy.\n        for (int p = K; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_by_item[item];\n        }\n\n        return bins;\n    }\n\n    static void erase_one(vector<int>& v, int x) {\n        for (int i = 0; i < (int)v.size(); ++i) {\n            if (v[i] == x) {\n                v.erase(v.begin() + i);\n                return;\n            }\n        }\n    }\n\n    void local_improve(vector<Bin>& bins, const vector<char>& fixed) {\n        for (int iter = 0; iter < 300; ++iter) {\n            int hi = 0, lo = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load > bins[hi].est_load) hi = j;\n                if (bins[j].est_load < bins[lo].est_load) lo = j;\n            }\n            if (hi == lo) break;\n\n            long double A = bins[hi].est_load;\n            long double B = bins[lo].est_load;\n            long double best_diff = fabsl(A - B);\n\n            int best_type = 0; // 0 none, 1 move x hi->lo, 2 swap x<->y\n            int bx = -1, by = -1;\n\n            // Move one item from heavy to light\n            if ((int)bins[hi].items.size() > 1) {\n                for (int x : bins[hi].items) {\n                    if (fixed[x]) continue;\n                    long double w = est_by_item[x];\n                    long double nd = fabsl((A - w) - (B + w));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        best_type = 1;\n                        bx = x;\n                        by = -1;\n                    }\n                }\n            }\n\n            // Swap one item\n            for (int x : bins[hi].items) {\n                if (fixed[x]) continue;\n                long double wx = est_by_item[x];\n                for (int y : bins[lo].items) {\n                    if (fixed[y]) continue;\n                    long double wy = est_by_item[y];\n                    long double nd = fabsl((A - wx + wy) - (B - wy + wx));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        best_type = 2;\n                        bx = x;\n                        by = y;\n                    }\n                }\n            }\n\n            if (best_type == 0) break;\n\n            if (best_type == 1) {\n                erase_one(bins[hi].items, bx);\n                bins[lo].items.push_back(bx);\n                long double w = est_by_item[bx];\n                bins[hi].est_load -= w;\n                bins[lo].est_load += w;\n            } else {\n                erase_one(bins[hi].items, bx);\n                erase_one(bins[lo].items, by);\n                bins[hi].items.push_back(by);\n                bins[lo].items.push_back(bx);\n                long double wx = est_by_item[bx];\n                long double wy = est_by_item[by];\n                bins[hi].est_load += wy - wx;\n                bins[lo].est_load += wx - wy;\n            }\n        }\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        lgD = ceil_log2_int(D);\n\n        insc.assign(N + 1, 0);\n        for (int k = 2; k <= N; ++k) insc[k] = insc[k - 1] + ceil_log2_int(k);\n\n        H.assign(N + 1, 0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0L / i;\n\n        est_by_pos.assign(N, 0);\n        for (int p = 0; p < N; ++p) {\n            est_by_pos[p] = H[N] - H[p];\n        }\n\n        vector<int> order;\n        int K_actual = 0;\n\n        if (Q >= insc[N]) {\n            // Exact sort all items, then use remaining queries for exact bin placement\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            order = exact_sort_items(all);\n\n            int rem = Q - used;\n            K_actual = D;\n            if (lgD > 0) {\n                K_actual = min(N, D + rem / lgD);\n            } else {\n                K_actual = N;\n            }\n        } else {\n            // Tournament coarse order first\n            vector<int> coarse = tournament_order();\n            int R = Q - used;\n\n            int Mbest = 0;\n            for (int m = 0; m <= N; ++m) {\n                if (insc[m] <= R) Mbest = m;\n            }\n\n            int Kbest = 0;\n            for (int k = D; k <= N; ++k) {\n                long long need = (long long)insc[k] + 1LL * (k - D) * lgD;\n                if (need <= R) Kbest = k;\n            }\n\n            long double utilA = -1e100L;\n            if (Kbest >= D) {\n                utilA = (long double)Kbest + (long double)(Kbest - D) * (2.0L / max(1, lgD));\n            }\n            long double utilB = (long double)Mbest;\n\n            int M = 0;\n            if (Kbest >= D && utilA > utilB) {\n                M = Kbest;\n                K_actual = Kbest;\n            } else {\n                M = Mbest;\n                K_actual = 0;\n            }\n\n            vector<int> prefix(coarse.begin(), coarse.begin() + M);\n            vector<int> exact_prefix = exact_sort_items(prefix);\n\n            order.reserve(N);\n            for (int x : exact_prefix) order.push_back(x);\n            for (int i = M; i < N; ++i) order.push_back(coarse[i]);\n        }\n\n        // Estimated weight per item from final approximate order position\n        est_by_item.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_by_item[order[p]] = est_by_pos[p];\n\n        vector<Bin> bins;\n        vector<char> fixed(N, 0);\n\n        if (K_actual >= D) {\n            for (int p = 0; p < K_actual; ++p) fixed[order[p]] = 1;\n            bins = hybrid_assign(order, K_actual);\n        } else {\n            bins = estimated_assign_all(order);\n        }\n\n        local_improve(bins, fixed);\n\n        // Fill remaining queries with dummy queries\n        while (used < Q) {\n            vector<int> L{0}, R{1};\n            ask(L, R);\n        }\n\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b].items) ans[x] = b;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<long long> bit;\n    Fenwick(int n = 0) { init(n); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, long long val) {\n        for (; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    long long sum_prefix(int idx) const {\n        long long s = 0;\n        for (; idx > 0; idx -= idx & -idx) s += bit[idx];\n        return s;\n    }\n    long long sum(int l, int r) const {\n        if (l > r) return 0;\n        return sum_prefix(r) - sum_prefix(l - 1);\n    }\n};\n\nstruct Solver {\n    static constexpr int LMAX = 4;\n    static constexpr long long CHUNK_PENALTY = 12;\n\n    int n, m;\n    vector<vector<int>> st;              // bottom -> top\n    vector<pair<int,int>> ans;\n    int cur = 1;\n\n    long long urgency(int x) const {\n        // 1..5 for n=200\n        return 1 + (n - x) / 40;\n    }\n\n    void remove_possible() {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ans.push_back({cur, 0});\n                    cur++;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    pair<int,int> find_box(int v) const {\n        for (int i = 0; i < m; 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    void move_by_value(int v, int dst) {\n        for (int s = 0; s < m; s++) {\n            for (int j = 0; j < (int)st[s].size(); j++) {\n                if (st[s][j] == v) {\n                    vector<int> seg(st[s].begin() + j, st[s].end());\n                    st[s].erase(st[s].begin() + j, st[s].end());\n                    st[dst].insert(st[dst].end(), seg.begin(), seg.end());\n                    ans.push_back({v, dst + 1});\n                    return;\n                }\n            }\n        }\n    }\n\n    long long cross_cost(const vector<int>& lower, const vector<int>& upper) const {\n        long long cost = 0;\n        for (int x : lower) {\n            long long w = urgency(x);\n            for (int y : upper) {\n                if (x < y) cost += w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> make_chunks(const vector<int>& a) const {\n        int t = (int)a.size();\n        if (t == 0) return {};\n\n        vector<vector<long long>> bad(t, vector<long long>(t, 0));\n        for (int l = 0; l < t; l++) {\n            Fenwick fw(n + 2);\n            long long cur_bad = 0;\n            for (int r = l; r < t; r++) {\n                cur_bad += fw.sum(1, a[r] - 1); // previous smaller values below current\n                bad[l][r] = cur_bad;\n                fw.add(a[r], urgency(a[r]));\n            }\n        }\n\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> dp(LMAX + 1, vector<long long>(t + 1, INF));\n        vector<vector<int>> prv(LMAX + 1, vector<int>(t + 1, -1));\n        dp[0][0] = 0;\n\n        for (int k = 1; k <= LMAX; k++) {\n            for (int i = 1; i <= t; i++) {\n                for (int l = 0; l < i; l++) {\n                    if (dp[k - 1][l] == INF) continue;\n                    long long cand = dp[k - 1][l] + bad[l][i - 1];\n                    if (cand < dp[k][i]) {\n                        dp[k][i] = cand;\n                        prv[k][i] = l;\n                    }\n                }\n            }\n        }\n\n        long long best_score = INF;\n        int best_k = 1;\n        for (int k = 1; k <= LMAX; k++) {\n            if (dp[k][t] == INF) continue;\n            long long score = dp[k][t] + CHUNK_PENALTY * k;\n            if (score < best_score) {\n                best_score = score;\n                best_k = k;\n            }\n        }\n\n        vector<pair<int,int>> chunks_rev;\n        int i = t, k = best_k;\n        while (k > 0) {\n            int l = prv[k][i];\n            chunks_rev.push_back({l, i - 1});\n            i = l;\n            k--;\n        }\n        reverse(chunks_rev.begin(), chunks_rev.end());\n        return chunks_rev;\n    }\n\n    int choose_destination(int src, const vector<int>& chunk) const {\n        long long best_score = (1LL << 60);\n        int best_dst = -1;\n\n        for (int d = 0; d < m; d++) {\n            if (d == src) continue;\n            long long c = cross_cost(st[d], chunk);\n            long long score = c * 1000LL + (long long)st[d].size();\n            if (score < best_score) {\n                best_score = score;\n                best_dst = d;\n            }\n        }\n        return best_dst;\n    }\n\n    void solve() {\n        remove_possible();\n\n        while (cur <= n) {\n            auto [s, pos] = find_box(cur);\n            vector<int> blockers(st[s].begin() + pos + 1, st[s].end());\n\n            auto chunks = make_chunks(blockers);\n\n            // Move from top chunk to bottom chunk.\n            for (int idx = (int)chunks.size() - 1; idx >= 0; idx--) {\n                auto [l, r] = chunks[idx];\n                vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n                int dst = choose_destination(s, chunk);\n                move_by_value(blockers[l], dst);\n            }\n\n            remove_possible();\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.n >> solver.m;\n    solver.st.assign(solver.m, {});\n    int h = solver.n / solver.m;\n    for (int i = 0; i < solver.m; i++) {\n        solver.st[i].resize(h);\n        for (int j = 0; j < h; j++) cin >> solver.st[i][j];\n    }\n\n    solver.solve();\n\n    for (auto [v, i] : solver.ans) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(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() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct EvalResult {\n    long double score;\n    vector<long long> contrib;\n    vector<int> cnt;\n};\n\nstruct Params {\n    double a_pot;\n    double b_deg;\n    double noise;\n    double straight;\n};\n\nint N, Vn;\nvector<vector<int>> g;\nvector<int> dirt;\nvector<double> potv;\n\nstatic inline int vid(int r, int c, int N) { return r * N + c; }\n\nbool same_dir(int p, int v, int u) {\n    if (p < 0) return false;\n    int pr = p / N, pc = p % N;\n    int vr = v / N, vc = v % N;\n    int ur = u / N, uc = u % N;\n    return (vr - pr == ur - vr) && (vc - pc == uc - vc);\n}\n\nEvalResult evaluate_route(const vector<int>& seq, bool need_detail = true) {\n    int L = (int)seq.size() - 1;\n\n    vector<int> first(Vn, -1), last(Vn, -1), cnt(Vn, 0);\n    vector<long long> gapsum(Vn, 0);\n\n    for (int t = 1; t <= L; t++) {\n        int v = seq[t];\n        cnt[v]++;\n        if (first[v] == -1) {\n            first[v] = last[v] = t;\n        } else {\n            long long gap = t - last[v];\n            gapsum[v] += gap * (gap - 1) / 2;\n            last[v] = t;\n        }\n    }\n\n    long double total = 0;\n    vector<long long> contrib;\n    if (need_detail) contrib.assign(Vn, 0);\n\n    for (int v = 0; v < Vn; v++) {\n        if (cnt[v] == 0) {\n            // illegal / should not happen\n            EvalResult bad;\n            bad.score = 1e100L;\n            return bad;\n        }\n        long long gap = first[v] + L - last[v];\n        gapsum[v] += gap * (gap - 1) / 2;\n        long long c = gapsum[v] * 1LL * dirt[v];\n        total += (long double)c;\n        if (need_detail) contrib[v] = c;\n    }\n\n    EvalResult res;\n    res.score = total / (long double)L;\n    if (need_detail) {\n        res.contrib = move(contrib);\n        res.cnt = move(cnt);\n    }\n    return res;\n}\n\nvector<int> build_tree_route(const Params& P, RNG& rng) {\n    vector<vector<int>> children(Vn);\n    vector<char> vis(Vn, 0);\n\n    function<void(int,int)> dfs = [&](int v, int p) {\n        vis[v] = 1;\n        while (true) {\n            int best = -1;\n            double best_sc = -1e100;\n\n            for (int to : g[v]) {\n                if (vis[to]) continue;\n                int forward_deg = 0;\n                for (int w : g[to]) {\n                    if (!vis[w] && w != v) forward_deg++;\n                }\n                double sc = P.a_pot * potv[to]\n                          - P.b_deg * forward_deg\n                          + P.noise * rng.next_double();\n                if (same_dir(p, v, to)) sc += P.straight;\n\n                if (sc > best_sc) {\n                    best_sc = sc;\n                    best = to;\n                }\n            }\n            if (best == -1) break;\n            children[v].push_back(best);\n            dfs(best, v);\n        }\n    };\n\n    dfs(0, -1);\n\n    vector<int> seq;\n    seq.reserve(2 * Vn + 5);\n    seq.push_back(0);\n\n    function<void(int)> tour = [&](int v) {\n        for (int to : children[v]) {\n            seq.push_back(to);\n            tour(to);\n            seq.push_back(v);\n        }\n    };\n    tour(0);\n    return seq;\n}\n\nvector<int> apply_shuttle(const vector<int>& seq, int x, int y, int step, int offset) {\n    int L = (int)seq.size() - 1;\n    vector<int> res;\n    res.reserve(seq.size() + 64);\n\n    res.push_back(seq[0]);\n    int occ = 0;\n    bool inserted = false;\n\n    for (int i = 0; i < L; i++) {\n        int cur = seq[i];\n        int nxt = seq[i + 1];\n\n        if (cur == y) {\n            if (occ % step == offset) {\n                res.push_back(x);\n                res.push_back(y);\n                inserted = true;\n            }\n            occ++;\n        }\n        res.push_back(nxt);\n    }\n\n    if (!inserted) return {};\n    if ((int)res.size() - 1 > 100000) return {};\n    return res;\n}\n\nstring seq_to_moves(const vector<int>& seq) {\n    string ans;\n    ans.reserve(seq.size());\n    for (int i = 1; i < (int)seq.size(); i++) {\n        int a = seq[i - 1], b = seq[i];\n        int ar = a / N, ac = a % N;\n        int br = b / N, bc = b % N;\n        if (br == ar - 1 && bc == ac) ans.push_back('U');\n        else if (br == ar + 1 && bc == ac) ans.push_back('D');\n        else if (br == ar && bc == ac - 1) ans.push_back('L');\n        else if (br == ar && bc == ac + 1) ans.push_back('R');\n        else {\n            // Should never happen.\n            ans.push_back('?');\n        }\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    Vn = N * N;\n\n    vector<string> h(N - 1), v(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\n    dirt.assign(Vn, 0);\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirt[vid(i, j, N)];\n        }\n    }\n\n    g.assign(Vn, {});\n    for (int i = 0; i < N - 1; i++) {\n        for (int j = 0; j < N; j++) {\n            if (h[i][j] == '0') {\n                int a = vid(i, j, N);\n                int b = vid(i + 1, j, N);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N - 1; j++) {\n            if (v[i][j] == '0') {\n                int a = vid(i, j, N);\n                int b = vid(i, j + 1, N);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n\n    // Local dirt potential: own dirt + discounted nearby dirt within distance 3.\n    potv.assign(Vn, 0.0);\n    for (int s = 0; s < Vn; s++) {\n        potv[s] += dirt[s];\n        vector<int> dist(Vn, -1);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int x = q.front(); q.pop();\n            if (dist[x] == 3) continue;\n            for (int to : g[x]) {\n                if (dist[to] != -1) continue;\n                dist[to] = dist[x] + 1;\n                q.push(to);\n                if (dist[to] == 1) potv[s] += 0.45 * dirt[to];\n                else if (dist[to] == 2) potv[s] += 0.18 * dirt[to];\n                else if (dist[to] == 3) potv[s] += 0.06 * dirt[to];\n            }\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\n    RNG rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<Params> fixed_params = {\n        {1.00, 220.0,   0.0, 120.0},\n        {1.00, 260.0, 160.0, 120.0},\n        {1.15, 180.0, 200.0, 150.0},\n        {0.85, 320.0, 280.0,  80.0},\n        {1.00, 100.0, 380.0, 200.0},\n        {1.20,  50.0, 450.0, 220.0},\n        {0.90, 420.0, 500.0,  50.0},\n        {1.35, 140.0, 120.0, 100.0}\n    };\n\n    vector<int> best_seq;\n    long double best_score = 1e100L;\n\n    // Initial deterministic candidate.\n    {\n        Params P = fixed_params[0];\n        auto seq = build_tree_route(P, rng);\n        auto ev = evaluate_route(seq, false);\n        best_score = ev.score;\n        best_seq = move(seq);\n    }\n\n    // Randomized tree search.\n    int iter = 0;\n    while (elapsed() < 0.60) {\n        Params P;\n        if (iter < (int)fixed_params.size()) {\n            P = fixed_params[iter];\n        } else {\n            P.a_pot = 0.75 + 0.8 * rng.next_double();\n            P.b_deg = 20.0 + 480.0 * rng.next_double();\n            P.noise = 50.0 + 650.0 * rng.next_double();\n            P.straight = 0.0 + 240.0 * rng.next_double();\n        }\n        auto seq = build_tree_route(P, rng);\n        auto ev = evaluate_route(seq, false);\n        if (ev.score < best_score) {\n            best_score = ev.score;\n            best_seq = move(seq);\n        }\n        iter++;\n    }\n\n    // Greedy shuttle insertions.\n    vector<int> cur_seq = best_seq;\n    EvalResult cur_ev = evaluate_route(cur_seq, true);\n\n    const vector<pair<int,int>> patterns = {\n        {1, 0},\n        {2, 0}, {2, 1},\n        {3, 0}, {3, 1}, {3, 2}\n    };\n\n    for (int round = 0; round < 20 && elapsed() < 1.92; round++) {\n        if ((int)cur_seq.size() - 1 > 95000) break;\n\n        vector<int> order(Vn);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return cur_ev.contrib[a] > cur_ev.contrib[b];\n        });\n\n        int topM = min(Vn, ((int)cur_seq.size() <= 12000 ? 100 : 60));\n\n        long double local_best_score = cur_ev.score;\n        vector<int> local_best_seq;\n\n        for (int ii = 0; ii < topM && elapsed() < 1.90; ii++) {\n            int x = order[ii];\n            if (x == 0) continue;\n\n            for (int y : g[x]) {\n                for (auto [step, offset] : patterns) {\n                    auto cand = apply_shuttle(cur_seq, x, y, step, offset);\n                    if (cand.empty()) continue;\n\n                    auto ev = evaluate_route(cand, false);\n                    if (ev.score + 1e-12L < local_best_score) {\n                        local_best_score = ev.score;\n                        local_best_seq = move(cand);\n                    }\n                }\n            }\n        }\n\n        if (local_best_seq.empty()) break;\n        cur_seq = move(local_best_seq);\n        cur_ev = evaluate_route(cur_seq, true);\n    }\n\n    string ans = seq_to_moves(cur_seq);\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int INF = 1e9;\n\nstruct Solver {\n    int N, M;\n    int si, sj;\n    vector<string> board;\n    vector<string> words;\n    vector<pair<int,int>> posByChar[26];\n\n    vector<vector<int>> ov;          // overlap length [i][j] in [0,4]\n    vector<int> startApprox;         // approximate typing cost for first word\n    vector<vector<int>> edgeApprox;  // approximate typing cost to append j after i\n    vector<int> startLen;            // = 5\n    vector<vector<int>> edgeLen;     // = 5 - overlap\n\n    inline int dist(const pair<int,int>& a, const pair<int,int>& b) const {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    int overlap5(const string& a, const string& b) {\n        for (int k = 4; k >= 0; --k) {\n            bool ok = true;\n            for (int t = 0; t < k; ++t) {\n                if (a[5 - k + t] != b[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    // Exact min cost to type string s, starting with finger already on\n    // some occurrence of prevChar, with zero initial cost.\n    int cost_from_prev_char(int prevChar, const string& s) {\n        if (s.empty()) return 0;\n        const auto& initList = posByChar[prevChar];\n        vector<int> dp(initList.size(), 0), ndp;\n        const vector<pair<int,int>>* prevList = &initList;\n\n        for (char ch : s) {\n            int c = ch - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    // Exact min cost to type string s from the initial finger position.\n    int cost_from_start(const string& s) {\n        if (s.empty()) return 0;\n        int c0 = s[0] - 'A';\n        const auto& firstList = posByChar[c0];\n        vector<int> dp(firstList.size()), ndp;\n        for (int i = 0; i < (int)firstList.size(); ++i) {\n            dp[i] = abs(si - firstList[i].first) + abs(sj - firstList[i].second) + 1;\n        }\n        const vector<pair<int,int>>* prevList = &firstList;\n\n        for (int p = 1; p < (int)s.size(); ++p) {\n            int c = s[p] - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    void preprocess() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                posByChar[board[i][j] - 'A'].push_back({i, j});\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                ov[i][j] = overlap5(words[i], words[j]);\n            }\n        }\n\n        startApprox.assign(M, 0);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        startLen.assign(M, 5);\n        edgeLen.assign(M, vector<int>(M, 5));\n\n        for (int i = 0; i < M; ++i) {\n            startApprox[i] = cost_from_start(words[i]);\n        }\n\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                int r = ov[i][j];\n                string chunk = words[j].substr(r);\n                edgeApprox[i][j] = cost_from_prev_char(words[i][4] - 'A', chunk);\n                edgeLen[i][j] = 5 - r;\n            }\n        }\n    }\n\n    int insertion_delta(\n        const vector<int>& path,\n        int x, int pos,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int m = (int)path.size();\n        if (m == 0) return startC[x];\n        if (pos == 0) {\n            return startC[x] + edgeC[x][path[0]] - startC[path[0]];\n        } else if (pos == m) {\n            return edgeC[path[m - 1]][x];\n        } else {\n            return edgeC[path[pos - 1]][x] + edgeC[x][path[pos]] - edgeC[path[pos - 1]][path[pos]];\n        }\n    }\n\n    vector<int> build_order_cheapest_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        if (a == -1) {\n            path.push_back(0);\n            used[0] = 1;\n        } else {\n            path.push_back(a);\n            used[a] = 1;\n            if (b != -1) {\n                path.push_back(b);\n                used[b] = 1;\n            }\n        }\n\n        while ((int)path.size() < M) {\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n        return path;\n    }\n\n    vector<int> improve_relocate(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int n = (int)path.size();\n        for (int iter = 0; iter < 200; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (int i = 0; i < n; ++i) {\n                int x = path[i];\n\n                int remDelta = 0;\n                if (n == 1) {\n                    remDelta = 0;\n                } else if (i == 0) {\n                    int b = path[1];\n                    remDelta = startC[b] - startC[x] - edgeC[x][b];\n                } else if (i == n - 1) {\n                    int a = path[n - 2];\n                    remDelta = -edgeC[a][x];\n                } else {\n                    int a = path[i - 1];\n                    int b = path[i + 1];\n                    remDelta = edgeC[a][b] - edgeC[a][x] - edgeC[x][b];\n                }\n\n                for (int j = 0; j <= n - 1; ++j) {\n                    if (j == i) continue; // no-op\n\n                    int left = -1, right = -1;\n                    if (j < i) {\n                        left = (j == 0 ? -1 : path[j - 1]);\n                        right = path[j];\n                    } else { // j > i\n                        left = path[j];\n                        right = (j == n - 1 ? -1 : path[j + 1]);\n                    }\n\n                    int insDelta = 0;\n                    if (left == -1) {\n                        insDelta = startC[x] + edgeC[x][right] - startC[right];\n                    } else if (right == -1) {\n                        insDelta = edgeC[left][x];\n                    } else {\n                        insDelta = edgeC[left][x] + edgeC[x][right] - edgeC[left][right];\n                    }\n\n                    int delta = remDelta + insDelta;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            int x = path[bestI];\n            path.erase(path.begin() + bestI);\n            path.insert(path.begin() + bestJ, x);\n        }\n        return path;\n    }\n\n    string build_string(const vector<int>& order) {\n        string s = words[order[0]];\n        s.reserve(5 + 4 * M);\n        for (int k = 1; k < M; ++k) {\n            int i = order[k - 1];\n            int j = order[k];\n            int r = ov[i][j];\n            s += words[j].substr(r);\n        }\n        return s;\n    }\n\n    pair<int, vector<pair<int,int>>> exact_positions_for_string(const string& s) {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp, ndp;\n        const vector<pair<int,int>>* prevList = nullptr;\n\n        for (int t = 0; t < L; ++t) {\n            int c = s[t] - 'A';\n            const auto& curList = posByChar[c];\n            parent[t].assign(curList.size(), -1);\n            ndp.assign(curList.size(), INF);\n\n            if (t == 0) {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    ndp[j] = abs(si - curList[j].first) + abs(sj - curList[j].second) + 1;\n                }\n            } else {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    int best = INF, bestPrev = -1;\n                    for (int i = 0; i < (int)prevList->size(); ++i) {\n                        int cand = dp[i] + dist((*prevList)[i], curList[j]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestPrev = i;\n                        }\n                    }\n                    ndp[j] = best;\n                    parent[t][j] = bestPrev;\n                }\n            }\n\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n\n        int lastIdx = min_element(dp.begin(), dp.end()) - dp.begin();\n        int bestCost = dp[lastIdx];\n\n        vector<pair<int,int>> ops(L);\n        int idx = lastIdx;\n        for (int t = L - 1; t >= 0; --t) {\n            int c = s[t] - 'A';\n            ops[t] = posByChar[c][idx];\n            idx = parent[t][idx];\n        }\n\n        return {bestCost, ops};\n    }\n\n    void try_objective(\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps\n    ) {\n        vector<tuple<int,int,int>> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                pairs.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(pairs.begin(), pairs.end());\n\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            auto [c, a, b] = pairs[idx];\n            (void)c;\n\n            auto order = build_order_cheapest_insertion(a, b, startC, edgeC);\n            order = improve_relocate(order, startC, edgeC);\n\n            string s = build_string(order);\n            if ((int)s.size() > 5000) continue;\n\n            auto [cost, ops] = exact_positions_for_string(s);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestOps = move(ops);\n            }\n        }\n    }\n\n    void solve() {\n        preprocess();\n\n        int bestCost = INF;\n        vector<pair<int,int>> bestOps;\n\n        if (M == 1) {\n            auto res = exact_positions_for_string(words[0]);\n            bestOps = move(res.second);\n        } else {\n            // Keyboard-aware objective\n            try_objective(startApprox, edgeApprox, 20, bestCost, bestOps);\n\n            // Length-oriented objective\n            try_objective(startLen, edgeLen, 12, bestCost, bestOps);\n\n            // Also try: build by length, then polish by typing-cost objective\n            vector<tuple<int,int,int>> pairs;\n            for (int a = 0; a < M; ++a) {\n                for (int b = 0; b < M; ++b) if (a != b) {\n                    pairs.emplace_back(startLen[a] + edgeLen[a][b], a, b);\n                }\n            }\n            sort(pairs.begin(), pairs.end());\n            int use = min(12, (int)pairs.size());\n            for (int idx = 0; idx < use; ++idx) {\n                auto [c, a, b] = pairs[idx];\n                (void)c;\n                auto order = build_order_cheapest_insertion(a, b, startLen, edgeLen);\n                order = improve_relocate(order, startLen, edgeLen);\n                order = improve_relocate(order, startApprox, edgeApprox);\n\n                string s = build_string(order);\n                if ((int)s.size() > 5000) continue;\n\n                auto [cost, ops] = exact_positions_for_string(s);\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestOps = move(ops);\n                }\n            }\n        }\n\n        // Fallback (should not happen)\n        if (bestOps.empty()) {\n            string s;\n            for (auto& w : words) s += w;\n            auto [cost, ops] = exact_positions_for_string(s);\n            bestOps = move(ops);\n        }\n\n        for (auto [i, j] : bestOps) {\n            cout << i << ' ' << j << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M;\n    cin >> solver.si >> solver.sj;\n    solver.board.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.board[i];\n    solver.words.resize(solver.M);\n    for (int i = 0; i < solver.M; ++i) cin >> solver.words[i];\n\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 20;\nstatic constexpr int MAXC = 400;\nstatic constexpr int MAXQ = 56; // 2N + 16 <= 56\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct Placement {\n    vector<uint16_t> cells;              // covered board cells\n    array<uint8_t, MAXQ> contrib{};      // contribution to row/col/block features\n    vector<uint16_t> drill_ids;          // drilled-cell indices covered by this placement\n    bool valid = true;\n};\n\nstruct Field {\n    vector<pair<int,int>> shape;\n    vector<Placement> ps;\n    int valid_count = 0;\n};\n\nstruct SavedState {\n    array<short, MAXM> choice{};\n    int exact_err = INT_MAX;\n    double noisy = 1e100;\n};\n\nstruct SearchState {\n    array<short, MAXM> choice{};\n    array<int, MAXQ> feat{};\n    vector<int> pred; // predicted reserve counts on drilled cells\n    int exact_err = 0;\n    double noisy = 0.0;\n};\n\nstruct Solver {\n    int N, M;\n    double eps;\n    double alpha;\n\n    vector<Field> fields;\n    int C;\n\n    // initial aggregate features\n    int Q = 0;\n    array<double, MAXQ> estQ{};\n    array<double, MAXQ> wQ{};\n    array<int, MAXQ> qSize{};\n\n    // block partition\n    int rb[5], cb[5];\n    int block_id[MAXN][MAXN];\n    int block_area[16];\n\n    // cover list: which placements cover a cell\n    vector<vector<pair<uint8_t,uint16_t>>> coverList;\n\n    // drilled info\n    vector<int> drill_cells; // cell ids in drill order\n    vector<int> drill_obs;   // exact v(cell)\n    vector<int> cell_to_drill; // size C, -1 if not drilled\n    vector<int> exact_v;       // size C, -1 if unknown\n\n    // search scratch\n    vector<int> mark, chg, aff;\n    int iter_mark = 1;\n\n    // time\n    chrono::steady_clock::time_point st;\n\n    Solver(): C(0) {}\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool better_pair(int e1, double n1, int e2, double n2) const {\n        if (e1 != e2) return e1 < e2;\n        return n1 + 1e-12 < n2;\n    }\n\n    int ask_divination(const vector<int>& cells) {\n        cout << \"q \" << cells.size();\n        for (int id : cells) {\n            int i = id / N, j = id % N;\n            cout << ' ' << i << ' ' << j;\n        }\n        cout << endl;\n        cout.flush();\n        int y;\n        cin >> y;\n        return y;\n    }\n\n    int ask_drill(int cell) {\n        int i = cell / N, j = cell % N;\n        cout << \"q 1 \" << i << ' ' << j << endl;\n        cout.flush();\n        int v;\n        cin >> v;\n        return v;\n    }\n\n    bool ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int id : cells) {\n            int i = id / N, j = id % N;\n            cout << ' ' << i << ' ' << j;\n        }\n        cout << endl;\n        cout.flush();\n        int ok;\n        cin >> ok;\n        return ok == 1;\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        alpha = 1.0 - 2.0 * eps;\n        C = N * N;\n        fields.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int d;\n            cin >> d;\n            fields[k].shape.resize(d);\n            for (int t = 0; t < d; ++t) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].shape[t] = {i, j};\n            }\n        }\n        cell_to_drill.assign(C, -1);\n        exact_v.assign(C, -1);\n        coverList.assign(C, {});\n    }\n\n    void build_blocks() {\n        for (int t = 0; t <= 4; ++t) {\n            rb[t] = (long long)t * N / 4;\n            cb[t] = (long long)t * N / 4;\n        }\n        memset(block_area, 0, sizeof(block_area));\n        for (int i = 0; i < N; ++i) {\n            int bi = 0;\n            while (!(rb[bi] <= i && i < rb[bi+1])) ++bi;\n            for (int j = 0; j < N; ++j) {\n                int bj = 0;\n                while (!(cb[bj] <= j && j < cb[bj+1])) ++bj;\n                int b = bi * 4 + bj;\n                block_id[i][j] = b;\n                block_area[b]++;\n            }\n        }\n    }\n\n    void enumerate_placements() {\n        Q = 2 * N + 16;\n        for (int k = 0; k < M; ++k) {\n            int max_i = 0, max_j = 0;\n            for (auto [i, j] : fields[k].shape) {\n                max_i = max(max_i, i);\n                max_j = max(max_j, j);\n            }\n\n            for (int di = 0; di + max_i < N; ++di) {\n                for (int dj = 0; dj + max_j < N; ++dj) {\n                    Placement p;\n                    p.contrib.fill(0);\n                    for (auto [si, sj] : fields[k].shape) {\n                        int i = di + si;\n                        int j = dj + sj;\n                        int id = i * N + j;\n                        p.cells.push_back((uint16_t)id);\n                        p.contrib[i]++;\n                        p.contrib[N + j]++;\n                        p.contrib[2 * N + block_id[i][j]]++;\n                    }\n                    int idx = (int)fields[k].ps.size();\n                    for (int id : p.cells) {\n                        coverList[id].push_back({(uint8_t)k, (uint16_t)idx});\n                    }\n                    fields[k].ps.push_back(std::move(p));\n                }\n            }\n            fields[k].valid_count = (int)fields[k].ps.size();\n        }\n    }\n\n    void initial_queries() {\n        // rows\n        for (int i = 0; i < N; ++i) {\n            vector<int> cells;\n            cells.reserve(N);\n            for (int j = 0; j < N; ++j) cells.push_back(i * N + j);\n            int y = ask_divination(cells);\n            int k = N;\n            qSize[i] = k;\n            estQ[i] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[i] = 1.0 / var_est;\n        }\n        // cols\n        for (int j = 0; j < N; ++j) {\n            vector<int> cells;\n            cells.reserve(N);\n            for (int i = 0; i < N; ++i) cells.push_back(i * N + j);\n            int y = ask_divination(cells);\n            int qi = N + j;\n            int k = N;\n            qSize[qi] = k;\n            estQ[qi] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[qi] = 1.0 / var_est;\n        }\n        // 4x4 blocks\n        for (int bi = 0; bi < 4; ++bi) {\n            for (int bj = 0; bj < 4; ++bj) {\n                vector<int> cells;\n                for (int i = rb[bi]; i < rb[bi+1]; ++i) {\n                    for (int j = cb[bj]; j < cb[bj+1]; ++j) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                int y = ask_divination(cells);\n                int b = bi * 4 + bj;\n                int qi = 2 * N + b;\n                int k = (int)cells.size();\n                qSize[qi] = k;\n                estQ[qi] = (y - k * eps) / alpha;\n                double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n                wQ[qi] = 1.0 / var_est;\n            }\n        }\n    }\n\n    void register_drill(int cell, int v) {\n        exact_v[cell] = v;\n        if (cell_to_drill[cell] == -1) {\n            int idx = (int)drill_cells.size();\n            cell_to_drill[cell] = idx;\n            drill_cells.push_back(cell);\n            drill_obs.push_back(v);\n\n            mark.resize(drill_cells.size(), 0);\n            chg.resize(drill_cells.size(), 0);\n\n            for (auto [fk, pi] : coverList[cell]) {\n                fields[fk].ps[pi].drill_ids.push_back((uint16_t)idx);\n            }\n        } else {\n            int idx = cell_to_drill[cell];\n            drill_obs[idx] = v;\n        }\n\n        if (v == 0) {\n            for (auto [fk, pi] : coverList[cell]) {\n                auto &pl = fields[fk].ps[pi];\n                if (pl.valid) {\n                    pl.valid = false;\n                    fields[fk].valid_count--;\n                }\n            }\n        }\n    }\n\n    double initial_noisy0() const {\n        double s = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            double r = -estQ[q];\n            s += wQ[q] * r * r;\n        }\n        return s;\n    }\n\n    void calc_delta_parts(const SearchState& s, int field_idx, int newp, int &dExact, double &dNoisy) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) {\n            dExact = 0;\n            dNoisy = 0.0;\n            return;\n        }\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        dNoisy = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            dNoisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n        }\n\n        dExact = 0;\n        if (drill_cells.empty()) return;\n\n        ++iter_mark;\n        if (iter_mark == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            iter_mark = 1;\n        }\n        aff.clear();\n\n        if (oldpl) {\n            for (int id : oldpl->drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]--;\n            }\n        }\n        for (int id : newpl.drill_ids) {\n            if (mark[id] != iter_mark) {\n                mark[id] = iter_mark;\n                chg[id] = 0;\n                aff.push_back(id);\n            }\n            chg[id]++;\n        }\n\n        for (int id : aff) {\n            int oc = s.pred[id];\n            int nc = oc + chg[id];\n            int obs = drill_obs[id];\n            dExact += (nc - obs) * (nc - obs) - (oc - obs) * (oc - obs);\n        }\n    }\n\n    void apply_change(SearchState& s, int field_idx, int newp) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) return;\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            s.noisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n            s.feat[q] += d;\n        }\n\n        if (!drill_cells.empty()) {\n            ++iter_mark;\n            if (iter_mark == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                iter_mark = 1;\n            }\n            aff.clear();\n\n            if (oldpl) {\n                for (int id : oldpl->drill_ids) {\n                    if (mark[id] != iter_mark) {\n                        mark[id] = iter_mark;\n                        chg[id] = 0;\n                        aff.push_back(id);\n                    }\n                    chg[id]--;\n                }\n            }\n            for (int id : newpl.drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]++;\n            }\n\n            for (int id : aff) {\n                int oc = s.pred[id];\n                int obs = drill_obs[id];\n                s.exact_err -= (oc - obs) * (oc - obs);\n                s.pred[id] += chg[id];\n                int nc = s.pred[id];\n                s.exact_err += (nc - obs) * (nc - obs);\n            }\n        }\n\n        s.choice[field_idx] = (short)newp;\n    }\n\n    bool usable_placement(int k, int p) const {\n        if (fields[k].valid_count == 0) return true;\n        return fields[k].ps[p].valid;\n    }\n\n    SearchState greedy_random_init() {\n        SearchState s;\n        s.choice.fill(-1);\n        s.feat.fill(0);\n        s.pred.assign(drill_cells.size(), 0);\n        s.exact_err = 0;\n        for (int obs : drill_obs) s.exact_err += obs * obs;\n        s.noisy = initial_noisy0();\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n        for (int k : order) {\n            struct Cand { int p; int e; double n; };\n            Cand best[3];\n            int bsz = 0;\n\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                int de;\n                double dn;\n                calc_delta_parts(s, k, p, de, dn);\n                int ne = s.exact_err + de;\n                double nn = s.noisy + dn;\n\n                Cand cur{p, ne, nn};\n                int pos = bsz;\n                for (int t = 0; t < bsz; ++t) {\n                    if (better_pair(cur.e, cur.n, best[t].e, best[t].n)) {\n                        pos = t;\n                        break;\n                    }\n                }\n                if (pos < 3) {\n                    for (int t = min(2, bsz); t > pos; --t) best[t] = best[t-1];\n                    best[pos] = cur;\n                    if (bsz < 3) ++bsz;\n                }\n            }\n\n            if (bsz == 0) continue;\n            int pick = 0;\n            if (bsz == 2) pick = rng.next_int(0, 1);\n            else if (bsz == 3) {\n                int r = rng.next_int(0, 5);\n                if (r <= 2) pick = 0;\n                else if (r <= 4) pick = 1;\n                else pick = 2;\n            }\n            apply_change(s, k, best[pick].p);\n        }\n        return s;\n    }\n\n    void local_descent(SearchState& s, int max_sweeps = 3) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < max_sweeps; ++sw) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n            for (int k : order) {\n                int bestp = s.choice[k];\n                int beste = s.exact_err;\n                double bestn = s.noisy;\n\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (!usable_placement(k, p)) continue;\n                    int de;\n                    double dn;\n                    calc_delta_parts(s, k, p, de, dn);\n                    int ne = s.exact_err + de;\n                    double nn = s.noisy + dn;\n                    if (better_pair(ne, nn, beste, bestn)) {\n                        beste = ne;\n                        bestn = nn;\n                        bestp = p;\n                    }\n                }\n\n                if (bestp != s.choice[k]) {\n                    apply_change(s, k, bestp);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    static bool same_choice(const SavedState& a, const SavedState& b, int M) {\n        for (int i = 0; i < M; ++i) if (a.choice[i] != b.choice[i]) return false;\n        return true;\n    }\n\n    void add_saved(vector<SavedState>& top, const SearchState& s, int keep = 8) {\n        SavedState cur;\n        cur.choice = s.choice;\n        cur.exact_err = s.exact_err;\n        cur.noisy = s.noisy;\n\n        for (auto &x : top) {\n            if (same_choice(x, cur, M)) {\n                if (better_pair(cur.exact_err, cur.noisy, x.exact_err, x.noisy)) x = cur;\n                return;\n            }\n        }\n        top.push_back(cur);\n        sort(top.begin(), top.end(), [&](const SavedState& a, const SavedState& b){\n            return better_pair(a.exact_err, a.noisy, b.exact_err, b.noisy);\n        });\n        if ((int)top.size() > keep) top.resize(keep);\n    }\n\n    vector<SavedState> search_states(int restarts) {\n        vector<SavedState> top;\n        for (int it = 0; it < restarts; ++it) {\n            if (elapsed_ms() > 2500.0) break;\n            SearchState s = greedy_random_init();\n            local_descent(s, 3);\n            add_saved(top, s, 8);\n        }\n        return top;\n    }\n\n    vector<char> union_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ(C, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = choice[k];\n            if (p < 0) continue;\n            for (int id : fields[k].ps[p].cells) occ[id] = 1;\n        }\n        return occ;\n    }\n\n    vector<int> union_cells_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ = union_from_choice(choice);\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (occ[id]) ans.push_back(id);\n        return ans;\n    }\n\n    bool confident_answer(const vector<SavedState>& top, int step, int heuristic_limit, vector<int>& ans_cells) {\n        vector<int> idxs;\n        for (int i = 0; i < (int)top.size(); ++i) {\n            if (top[i].exact_err == 0) idxs.push_back(i);\n        }\n        if (idxs.empty()) return false;\n\n        int use = min(5, (int)idxs.size());\n        auto base_union = union_from_choice(top[idxs[0]].choice);\n        for (int t = 1; t < use; ++t) {\n            auto u = union_from_choice(top[idxs[t]].choice);\n            if (u != base_union) return false;\n        }\n\n        int D = (int)drill_cells.size();\n        if (use >= 3 || D >= 8 || step + 1 >= heuristic_limit || M <= 3) {\n            ans_cells.clear();\n            for (int id = 0; id < C; ++id) if (base_union[id]) ans_cells.push_back(id);\n            return true;\n        }\n        return false;\n    }\n\n    int select_drill_cell_from_states(const vector<SavedState>& top) {\n        if (!top.empty()) {\n            int best_exact = top[0].exact_err;\n            vector<int> cand_idxs;\n            for (int i = 0; i < (int)top.size(); ++i) {\n                if (top[i].exact_err == best_exact) cand_idxs.push_back(i);\n            }\n            if (cand_idxs.size() >= 2) {\n                int S = min(6, (int)cand_idxs.size());\n                vector<double> sum(C, 0.0), sq(C, 0.0), occ(C, 0.0);\n\n                for (int t = 0; t < S; ++t) {\n                    const auto& ch = top[cand_idxs[t]].choice;\n                    vector<int> cnt(C, 0);\n                    for (int k = 0; k < M; ++k) {\n                        int p = ch[k];\n                        if (p < 0) continue;\n                        for (int id : fields[k].ps[p].cells) cnt[id]++;\n                    }\n                    for (int id = 0; id < C; ++id) {\n                        if (exact_v[id] != -1) continue;\n                        sum[id] += cnt[id];\n                        sq[id] += 1.0 * cnt[id] * cnt[id];\n                        occ[id] += (cnt[id] > 0 ? 1.0 : 0.0);\n                    }\n                }\n\n                double best_score = -1.0;\n                int best_cell = -1;\n                for (int id = 0; id < C; ++id) {\n                    if (exact_v[id] != -1) continue;\n                    double mean = sum[id] / S;\n                    double var = sq[id] / S - mean * mean;\n                    double p = occ[id] / S;\n                    double score = var + 0.25 * p * (1.0 - p);\n                    if (score > best_score + 1e-12) {\n                        best_score = score;\n                        best_cell = id;\n                    }\n                }\n                if (best_cell != -1 && best_score > 1e-6) return best_cell;\n            }\n        }\n\n        // fallback: independent coverage uncertainty over valid placements\n        vector<double> var(C, 0.0), ex(C, 0.0);\n        vector<int> cnt(C, 0);\n\n        for (int k = 0; k < M; ++k) {\n            fill(cnt.begin(), cnt.end(), 0);\n            int tot = 0;\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                ++tot;\n                for (int id : fields[k].ps[p].cells) cnt[id]++;\n            }\n            if (tot == 0) continue;\n            for (int id = 0; id < C; ++id) {\n                if (exact_v[id] != -1) continue;\n                if (cnt[id] == 0) continue;\n                double p = 1.0 * cnt[id] / tot;\n                var[id] += p * (1.0 - p);\n                ex[id] += p;\n            }\n        }\n\n        double best_score = -1.0;\n        int best_cell = -1;\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1) continue;\n            double score = var[id] + 0.05 * ex[id];\n            if (score > best_score + 1e-12) {\n                best_score = score;\n                best_cell = id;\n            }\n        }\n        if (best_cell != -1) return best_cell;\n\n        for (int id = 0; id < C; ++id) if (exact_v[id] == -1) return id;\n        return -1;\n    }\n\n    bool heuristic_phase() {\n        int heuristic_limit = min(18, 6 + M / 2 + (eps < 0.08 ? 4 : 0));\n        if (M <= 3) heuristic_limit = max(heuristic_limit, 14);\n\n        bool guessed_once = false;\n\n        for (int step = 0; step < heuristic_limit; ++step) {\n            if (elapsed_ms() > 2400.0) break;\n\n            int restarts = (step == 0 ? 18 : 8);\n            if (M <= 4) restarts += 4;\n            auto top = search_states(restarts);\n\n            vector<int> ans_cells;\n            if (!guessed_once && confident_answer(top, step, heuristic_limit, ans_cells)) {\n                guessed_once = true;\n                if (ask_answer(ans_cells)) return true;\n                // failed guess -> stop heuristic, go exhaustive for safety\n                return false;\n            }\n\n            int cell = select_drill_cell_from_states(top);\n            if (cell == -1) break;\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n        return false;\n    }\n\n    void exhaustive_finish() {\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1) {\n                int v = ask_drill(id);\n                register_drill(id, v);\n            }\n        }\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        bool ok = ask_answer(ans);\n        if (!ok) {\n            // Should not happen after full drilling, but just in case:\n            exit(0);\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n        read_input();\n        build_blocks();\n        enumerate_placements();\n        initial_queries();\n\n        if (heuristic_phase()) return;\n        exhaustive_finish();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Solver {\n    int W, D, N;\n    vector<vector<int>> a;              // sorted demands per day\n    vector<vector<int>> locProf;        // sorted local profile (without hidden leftover)\n    vector<int> locRem;                 // leftover hidden in last strip\n    vector<ll> locShort;                // shortage cost for local profile\n    vector<int> globProf;               // sorted global profile\n    int globRem = 0;                    // leftover hidden in last strip\n    vector<ll> globShort;               // shortage cost per day for global profile\n\n    Solver() {\n        cin >> W >> D >> N;\n        a.assign(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    }\n\n    static ll shortage_cost_day(const vector<int>& demand, const vector<int>& prof_sorted) {\n        ll s = 0;\n        for (int k = 0; k < (int)demand.size(); k++) {\n            ll area = 1000LL * prof_sorted[k];\n            if (area < demand[k]) s += demand[k] - area;\n        }\n        return 100LL * s;\n    }\n\n    // Greedy profile for one day, under the \"full-width horizontal strips\" model.\n    // c is kept nondecreasing.\n    pair<vector<int>, int> make_local_profile(int d) {\n        vector<int> c(N, 1);\n        int rem = 1000 - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue; // keep nondecreasing\n                int deficit = a[d][k] - 1000 * c[k];\n                int gain = deficit > 0 ? min(1000, deficit) : 0;\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    // Greedy global common profile.\n    pair<vector<int>, int> make_global_profile() {\n        vector<int> c(N, 1);\n        int rem = 1000 - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int gain = 0;\n                for (int d = 0; d < D; d++) {\n                    int deficit = a[d][k] - 1000 * c[k];\n                    if (deficit > 0) gain += min(1000, deficit);\n                }\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    // Transition cost between two prefix-cut arrays.\n    ll trans_cost_pref(const int* p1, const int* p2) const {\n        int len = N - 1;\n        int i = 0, j = 0, common = 0;\n        while (i < len && j < len) {\n            if (p1[i] == p2[j]) {\n                common++;\n                i++; j++;\n            } else if (p1[i] < p2[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return 2000LL * (len - common);\n    }\n\n    // Evaluate a permutation by running DP over two states:\n    // 0 = day-specific local profile\n    // 1 = global common profile\n    ll eval_perm(const vector<int>& perm) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        ll dpL = locShort[0];\n        ll dpG = globShort[0];\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob); // local -> global on day d\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);     // global -> local on day d\n\n            ll ndpL = min(dpL + llc, dpG + glc) + locShort[d];\n            ll ndpG = min(dpL + lgc, dpG) + globShort[d];\n\n            dpL = ndpL;\n            dpG = ndpG;\n        }\n        return min(dpL, dpG);\n    }\n\n    vector<int> descend_perm(vector<int> perm) const {\n        ll cur = eval_perm(perm);\n        for (int round = 0; round < 25; round++) {\n            ll best = cur;\n            int bi = -1, bj = -1;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    swap(perm[i], perm[j]);\n                    ll sc = eval_perm(perm);\n                    swap(perm[i], perm[j]);\n                    if (sc < best) {\n                        best = sc;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n            if (bi == -1) break;\n            swap(perm[bi], perm[bj]);\n            cur = best;\n        }\n        return perm;\n    }\n\n    vector<int> choose_best_perm() {\n        vector<ll> vol(N, 0), avg(N, 0);\n        for (int k = 0; k < N; k++) {\n            for (int d = 1; d < D; d++) vol[k] += llabs(locProf[d][k] - locProf[d - 1][k]);\n            for (int d = 0; d < D; d++) avg[k] += locProf[d][k];\n        }\n\n        vector<int> id(N), rev(N), v1(N), v2(N);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        iota(v1.begin(), v1.end(), 0);\n        sort(v1.begin(), v1.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avg[x] != avg[y]) return avg[x] < avg[y];\n            return x < y;\n        });\n\n        v2 = v1;\n        reverse(v2.begin(), v2.end());\n\n        vector<vector<int>> inits = {id, rev, v1, v2};\n        // deduplicate\n        vector<vector<int>> uniq;\n        for (auto &p : inits) {\n            bool ok = true;\n            for (auto &q : uniq) if (q == p) ok = false;\n            if (ok) uniq.push_back(p);\n        }\n\n        vector<int> bestPerm = uniq[0];\n        ll bestScore = (1LL << 62);\n\n        for (auto p : uniq) {\n            p = descend_perm(p);\n            ll sc = eval_perm(p);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestPerm = p;\n            }\n        }\n        // final polishing\n        bestPerm = descend_perm(bestPerm);\n        return bestPerm;\n    }\n\n    vector<int> reconstruct_states(const vector<int>& perm) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        vector<array<ll,2>> dp(D);\n        vector<array<int,2>> par(D);\n\n        dp[0][0] = locShort[0];\n        dp[0][1] = globShort[0];\n        par[0][0] = par[0][1] = -1;\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            // to local\n            ll cand0 = dp[d - 1][0] + llc;\n            ll cand1 = dp[d - 1][1] + glc;\n            if (cand0 <= cand1) {\n                dp[d][0] = cand0 + locShort[d];\n                par[d][0] = 0;\n            } else {\n                dp[d][0] = cand1 + locShort[d];\n                par[d][0] = 1;\n            }\n\n            // to global\n            cand0 = dp[d - 1][0] + lgc;\n            cand1 = dp[d - 1][1];\n            if (cand0 <= cand1) {\n                dp[d][1] = cand0 + globShort[d];\n                par[d][1] = 0;\n            } else {\n                dp[d][1] = cand1 + globShort[d];\n                par[d][1] = 1;\n            }\n        }\n\n        vector<int> state(D);\n        state[D - 1] = (dp[D - 1][0] <= dp[D - 1][1] ? 0 : 1);\n        for (int d = D - 1; d >= 1; d--) state[d - 1] = par[d][state[d]];\n        return state;\n    }\n\n    vector<int> build_local_layout(int d, const vector<int>& perm) const {\n        vector<int> x(N);\n        for (int i = 0; i < N; i++) x[i] = locProf[d][perm[i]];\n        x[N - 1] += locRem[d]; // hidden free slack\n        return x;\n    }\n\n    vector<int> build_global_layout(const vector<int>& perm) const {\n        vector<int> x(N);\n        for (int i = 0; i < N; i++) x[i] = globProf[perm[i]];\n        x[N - 1] += globRem; // hidden free slack\n        return x;\n    }\n\n    void solve() {\n        // Local profiles\n        locProf.assign(D, vector<int>(N));\n        locRem.assign(D, 0);\n        locShort.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            auto [c, rem] = make_local_profile(d);\n            locProf[d] = c;\n            locRem[d] = rem;\n            locShort[d] = shortage_cost_day(a[d], c);\n        }\n\n        // Global profile\n        auto [gc, grem] = make_global_profile();\n        globProf = gc;\n        globRem = grem;\n        globShort.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            globShort[d] = shortage_cost_day(a[d], globProf);\n        }\n\n        // Optimize permutation of strip heights\n        vector<int> perm = choose_best_perm();\n\n        // DP over local/global layouts\n        vector<int> state = reconstruct_states(perm);\n\n        // Output rectangles\n        for (int d = 0; d < D; d++) {\n            vector<int> x = (state[d] == 0 ? build_local_layout(d, perm) : build_global_layout(perm));\n\n            vector<int> top(N), bot(N);\n            int cur = 0;\n            for (int i = 0; i < N; i++) {\n                top[i] = cur;\n                cur += x[i];\n                bot[i] = cur;\n            }\n            // should exactly fill height 1000\n            if (cur != 1000) {\n                // fallback safety (should not happen)\n                bot[N - 1] += 1000 - cur;\n            }\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            stable_sort(ord.begin(), ord.end(), [&](int i, int j) {\n                if (x[i] != x[j]) return x[i] < x[j];\n                return i < j;\n            });\n\n            // reservation k gets the k-th smallest strip by area\n            for (int k = 0; k < N; k++) {\n                int idx = ord[k];\n                cout << top[idx] << ' ' << 0 << ' ' << bot[idx] << ' ' << 1000 << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 9;\nstatic constexpr int POS = 7;              // N - 2\nstatic constexpr int MAX_A = 20 * 7 * 7;   // 980\nstatic constexpr int CELL = 81;\nstatic constexpr int MOD = 998244353;\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 Action {\n    int m, p, q;\n    array<uint8_t, 9> cell;\n    array<int, 9> val;\n};\n\nstruct Solution {\n    array<int, CELL> r{};\n    array<uint8_t, MAX_A> cnt{};\n    int L = 0;\n    long long score = 0;\n};\n\nint M_in, K_in;\narray<int, CELL> init_r;\nvector<Action> actions;\nint A = 0;\n\ninline long long gain_add(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_remove(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_swap(const Solution& s, int rem_id, int add_id) {\n    if (rem_id == add_id) return 0;\n    const auto& rm = actions[rem_id];\n    const auto& ad = actions[add_id];\n\n    long long delta = 0;\n    bool used_ad[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = rm.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv - rm.val[i];\n        if (nv < 0) nv += MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (ad.cell[j] == idx) {\n                nv += ad.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_ad[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_ad[j]) {\n            int idx = ad.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + ad.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline long long gain_add_pair(const Solution& s, int a_id, int b_id) {\n    const auto& a = actions[a_id];\n    const auto& b = actions[b_id];\n\n    long long delta = 0;\n    bool used_b[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = a.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv + a.val[i];\n        if (nv >= MOD) nv -= MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (b.cell[j] == idx) {\n                nv += b.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_b[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_b[j]) {\n            int idx = b.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + b.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline void apply_add(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    ++s.cnt[aid];\n    ++s.L;\n}\n\ninline void apply_remove(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n}\n\nSolution make_base_solution() {\n    Solution s;\n    s.r = init_r;\n    s.cnt.fill(0);\n    s.L = 0;\n    s.score = 0;\n    for (int i = 0; i < CELL; ++i) s.score += s.r[i];\n    return s;\n}\n\ntemplate <class RNG>\nSolution build_greedy(bool randomized, RNG& rng) {\n    Solution s = make_base_solution();\n\n    for (int step = 0; step < K_in; ++step) {\n        vector<pair<long long, int>> cand;\n        cand.reserve(A);\n\n        long long best_gain = LLONG_MIN;\n        int best_id = -1;\n\n        for (int aid = 0; aid < A; ++aid) {\n            long long g = gain_add(s, aid);\n            if (g > best_gain) {\n                best_gain = g;\n                best_id = aid;\n            }\n            if (g > 0) cand.push_back({g, aid});\n        }\n\n        if (best_gain <= 0) break;\n\n        int pick = best_id;\n        if (randomized) {\n            sort(cand.begin(), cand.end(), [](auto& x, auto& y) {\n                return x.first > y.first;\n            });\n            int t = min<int>(8, cand.size());\n            int total_w = t * (t + 1) / 2; // rank-biased\n            int r = (int)(rng() % total_w);\n            int acc = 0;\n            for (int i = 0; i < t; ++i) {\n                acc += (t - i);\n                if (r < acc) {\n                    pick = cand[i].second;\n                    break;\n                }\n            }\n        }\n\n        apply_add(s, pick);\n    }\n\n    return s;\n}\n\nvoid hill_climb(Solution& s, const Timer& timer, double time_limit_sec) {\n    while (timer.elapsed() < time_limit_sec) {\n        long long best_delta = 0;\n        int best_type = 0; // 1 add, 2 remove, 3 swap, 4 pair-add\n        int best_a = -1, best_b = -1;\n\n        // Add\n        if (s.L < K_in) {\n            for (int aid = 0; aid < A; ++aid) {\n                long long g = gain_add(s, aid);\n                if (g > best_delta) {\n                    best_delta = g;\n                    best_type = 1;\n                    best_a = aid;\n                }\n            }\n        }\n\n        // Remove\n        if (s.L > 0) {\n            for (int aid = 0; aid < A; ++aid) {\n                if (!s.cnt[aid]) continue;\n                long long g = gain_remove(s, aid);\n                if (g > best_delta) {\n                    best_delta = g;\n                    best_type = 2;\n                    best_a = aid;\n                }\n            }\n        }\n\n        // Swap\n        if (s.L > 0) {\n            int outer_count = 0;\n            for (int rem = 0; rem < A; ++rem) {\n                if (!s.cnt[rem]) continue;\n                for (int add = 0; add < A; ++add) {\n                    if (add == rem) continue;\n                    long long g = gain_swap(s, rem, add);\n                    if (g > best_delta) {\n                        best_delta = g;\n                        best_type = 3;\n                        best_a = rem;\n                        best_b = add;\n                    }\n                }\n                if ((++outer_count & 7) == 0 && timer.elapsed() >= time_limit_sec) break;\n            }\n        }\n\n        // Pair add\n        if (best_delta <= 0 && s.L <= K_in - 2) {\n            for (int a = 0; a < A; ++a) {\n                for (int b = a; b < A; ++b) {\n                    long long g = gain_add_pair(s, a, b);\n                    if (g > best_delta) {\n                        best_delta = g;\n                        best_type = 4;\n                        best_a = a;\n                        best_b = b;\n                    }\n                }\n                if ((a & 15) == 0 && timer.elapsed() >= time_limit_sec) break;\n            }\n        }\n\n        if (best_delta <= 0) break;\n\n        if (best_type == 1) {\n            apply_add(s, best_a);\n        } else if (best_type == 2) {\n            apply_remove(s, best_a);\n        } else if (best_type == 3) {\n            apply_remove(s, best_a);\n            apply_add(s, best_b);\n        } else if (best_type == 4) {\n            apply_add(s, best_a);\n            apply_add(s, best_b);\n        } else {\n            break;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_in;\n    cin >> N_in >> M_in >> K_in;\n\n    for (int i = 0; i < N_in; ++i) {\n        for (int j = 0; j < N_in; ++j) {\n            cin >> init_r[i * N + j];\n        }\n    }\n\n    vector<array<array<int, 3>, 3>> stamps(M_in);\n    for (int m = 0; m < M_in; ++m) {\n        for (int i = 0; i < 3; ++i) {\n            for (int j = 0; j < 3; ++j) {\n                cin >> stamps[m][i][j];\n            }\n        }\n    }\n\n    actions.clear();\n    actions.reserve(M_in * POS * POS);\n    for (int m = 0; m < M_in; ++m) {\n        for (int p = 0; p <= N_in - 3; ++p) {\n            for (int q = 0; q <= N_in - 3; ++q) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                int t = 0;\n                for (int i = 0; i < 3; ++i) {\n                    for (int j = 0; j < 3; ++j) {\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.val[t] = stamps[m][i][j];\n                        ++t;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n    A = (int)actions.size();\n\n    Timer timer;\n    const double TIME_LIMIT = 1.92;\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count() ^\n        (uint64_t)(uintptr_t)new int\n    );\n\n    Solution best = build_greedy(false, rng);\n    hill_climb(best, timer, TIME_LIMIT);\n\n    while (timer.elapsed() < TIME_LIMIT) {\n        Solution cur = build_greedy(true, rng);\n        hill_climb(cur, timer, TIME_LIMIT);\n        if (cur.score > best.score) best = cur;\n    }\n\n    vector<int> ans;\n    ans.reserve(best.L);\n    for (int aid = 0; aid < A; ++aid) {\n        for (int c = 0; c < best.cnt[aid]; ++c) {\n            ans.push_back(aid);\n        }\n    }\n\n    cout << ans.size() << '\\n';\n    for (int aid : ans) {\n        const auto& ac = actions[aid];\n        cout << ac.m << ' ' << ac.p << ' ' << ac.q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int r, c;\n};\n\nstatic const int N = 5;\n\nstruct Crane {\n    int r, c;\n    int hold;      // -1 if none\n    bool alive;\n    bool large;\n};\n\nstruct Solver {\n    int A[N][N];\n\n    int board[N][N];              // placed container id, -1 if empty\n    int spawn_ptr[N];             // next index to spawn from each receiving row\n    bool dispatched[25];          // whether container already dispatched\n    int total_dispatched = 0;\n\n    Crane cranes[N];\n    string out[N];\n\n    deque<char> plan;             // current macro plan for the large crane\n\n    Solver() {\n        memset(board, -1, sizeof(board));\n        memset(dispatched, 0, sizeof(dispatched));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n    }\n\n    int manhattan(const Pos& a, const Pos& b) const {\n        return abs(a.r - b.r) + abs(a.c - b.c);\n    }\n\n    int current_need(int tr) const {\n        for (int x = 5 * tr; x < 5 * tr + 5; x++) {\n            if (!dispatched[x]) return x;\n        }\n        return 5 * tr + 5; // all done\n    }\n\n    int inversion_increase_if_dispatch_now(int b) const {\n        int tr = b / 5;\n        int cnt = 0;\n        for (int x = 5 * tr; x < b; x++) {\n            if (!dispatched[x]) cnt++;\n        }\n        return cnt;\n    }\n\n    vector<char> make_route(Pos cur, Pos dst) const {\n        vector<char> res;\n        while (cur.r < dst.r) res.push_back('D'), cur.r++;\n        while (cur.r > dst.r) res.push_back('U'), cur.r--;\n        while (cur.c < dst.c) res.push_back('R'), cur.c++;\n        while (cur.c > dst.c) res.push_back('L'), cur.c--;\n        return res;\n    }\n\n    deque<char> make_transport_plan(Pos src, Pos dst) const {\n        deque<char> q;\n        Pos cur{cranes[0].r, cranes[0].c};\n        auto p1 = make_route(cur, src);\n        for (char ch : p1) q.push_back(ch);\n        q.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) q.push_back(ch);\n        q.push_back('Q');\n        return q;\n    }\n\n    bool is_buffer_cell_empty(int r, int c) const {\n        if (c == 4) return false;\n        if (board[r][c] != -1) return false;\n        // cols 1..3 are always usable as buffers\n        if (1 <= c && c <= 3) return true;\n        // col 0 usable only after that input row is exhausted\n        if (c == 0 && spawn_ptr[r] == N) return true;\n        return false;\n    }\n\n    vector<Pos> available_buffer_cells() const {\n        vector<Pos> v;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= 3; c++) {\n                if (is_buffer_cell_empty(r, c)) v.push_back({r, c});\n            }\n        }\n        return v;\n    }\n\n    optional<pair<Pos, int>> find_container_on_board(int b) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (board[r][c] == b) return {{Pos{r, c}, b}};\n            }\n        }\n        return nullopt;\n    }\n\n    // Choose best currently visible \"need\" container to dispatch\n    optional<deque<char>> try_dispatch_visible_need() const {\n        struct Cand {\n            int gatePenalty;\n            int dist;\n            Pos src;\n            Pos dst;\n            bool ok = false;\n        } best;\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                if (b != current_need(tr)) continue;\n\n                Pos src{r, c};\n                Pos dst{tr, 4};\n                int gatePenalty = (c == 0 ? 0 : 1);\n                int dist = manhattan({cranes[0].r, cranes[0].c}, src) + manhattan(src, dst);\n\n                if (!best.ok ||\n                    tie(gatePenalty, dist) < tie(best.gatePenalty, best.dist)) {\n                    best = {gatePenalty, dist, src, dst, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    // Move a gate-front blocker into buffer\n    optional<deque<char>> try_store_blocker() const {\n        auto buf = available_buffer_cells();\n        if (buf.empty()) return nullopt;\n\n        struct Cand {\n            int gapToFutureNeed;\n            int frontEarlyCostNeg; // larger early cost is better => smaller negative\n            int distScore;\n            Pos src;\n            Pos dst;\n            bool ok = false;\n        } best;\n\n        bool foundFiniteGap = false;\n\n        for (int r = 0; r < N; r++) {\n            // only if this row still has active gate-front input container\n            if (board[r][0] == -1) continue;\n            // if spawn_ptr[r] == N and board[r][0] is just a leftover visible container,\n            // it is no longer \"blocking future spawn\", so not good for reveal.\n            if (spawn_ptr[r] == N) continue;\n\n            int frontPos = spawn_ptr[r] - 1; // visible front sequence index\n            int gap = 1e9;\n            for (int k = frontPos + 1; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                if (!dispatched[b] && b == current_need(tr)) {\n                    gap = k - frontPos;\n                    break;\n                }\n            }\n\n            int front = board[r][0];\n            int earlyCost = inversion_increase_if_dispatch_now(front);\n\n            Pos src{r, 0};\n            int bestDist = INT_MAX;\n            Pos bestDst{-1, -1};\n            int trFront = front / 5;\n            Pos frontGate{trFront, 4};\n\n            for (auto d : buf) {\n                int sc = manhattan(src, d) + manhattan(d, frontGate);\n                if (sc < bestDist) {\n                    bestDist = sc;\n                    bestDst = d;\n                }\n            }\n\n            if (gap < (int)1e9) {\n                foundFiniteGap = true;\n                Cand cur{gap, -earlyCost, bestDist, src, bestDst, true};\n                if (!best.ok ||\n                    tie(cur.gapToFutureNeed, cur.frontEarlyCostNeg, cur.distScore) <\n                    tie(best.gapToFutureNeed, best.frontEarlyCostNeg, best.distScore)) {\n                    best = cur;\n                }\n            }\n        }\n\n        if (!foundFiniteGap) {\n            // Fallback: move some active gate-front blocker anyway\n            for (int r = 0; r < N; r++) {\n                if (board[r][0] == -1) continue;\n                if (spawn_ptr[r] == N) continue;\n\n                int front = board[r][0];\n                int earlyCost = inversion_increase_if_dispatch_now(front);\n\n                Pos src{r, 0};\n                int bestDist = INT_MAX;\n                Pos bestDst{-1, -1};\n                int trFront = front / 5;\n                Pos frontGate{trFront, 4};\n\n                for (auto d : buf) {\n                    int sc = manhattan(src, d) + manhattan(d, frontGate);\n                    if (sc < bestDist) {\n                        bestDist = sc;\n                        bestDst = d;\n                    }\n                }\n\n                Cand cur{1000000000, -earlyCost, bestDist, src, bestDst, true};\n                if (!best.ok ||\n                    tie(cur.frontEarlyCostNeg, cur.distScore) <\n                    tie(best.frontEarlyCostNeg, best.distScore)) {\n                    best = cur;\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    // Forced: dispatch a visible non-need container with minimum inversion increase\n    optional<deque<char>> try_forced_early_dispatch() const {\n        struct Cand {\n            int invInc;\n            int gatePenalty;\n            int dist;\n            Pos src;\n            Pos dst;\n            bool ok = false;\n        } best;\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                if (b == current_need(tr)) continue; // would have been handled earlier\n\n                int invInc = inversion_increase_if_dispatch_now(b);\n                Pos src{r, c};\n                Pos dst{tr, 4};\n                int gatePenalty = (c == 0 ? 0 : 1);\n                int dist = manhattan({cranes[0].r, cranes[0].c}, src) + manhattan(src, dst);\n\n                if (!best.ok ||\n                    tie(invInc, gatePenalty, dist) < tie(best.invInc, best.gatePenalty, best.dist)) {\n                    best = {invInc, gatePenalty, dist, src, dst, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    deque<char> choose_next_plan() const {\n        if (auto p = try_dispatch_visible_need(); p.has_value()) return *p;\n        if (auto p = try_store_blocker(); p.has_value()) return *p;\n        if (auto p = try_forced_early_dispatch(); p.has_value()) return *p;\n        return {};\n    }\n\n    void step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blockedByHoldingCrane = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blockedByHoldingCrane = true;\n                    break;\n                }\n            }\n            if (blockedByHoldingCrane) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n    }\n\n    void apply_action(int idx, char act) {\n        Crane &cr = cranes[idx];\n        if (!cr.alive) return;\n\n        if (act == '.') {\n            return;\n        } else if (act == 'B') {\n            // Only legal if not holding\n            if (cr.hold != -1) {\n                cerr << \"Illegal B while holding\\n\";\n                exit(1);\n            }\n            cr.alive = false;\n            return;\n        } else if (act == 'P') {\n            if (cr.hold != -1 || board[cr.r][cr.c] == -1) {\n                cerr << \"Illegal P\\n\";\n                exit(1);\n            }\n            cr.hold = board[cr.r][cr.c];\n            board[cr.r][cr.c] = -1;\n            return;\n        } else if (act == 'Q') {\n            if (cr.hold == -1 || board[cr.r][cr.c] != -1) {\n                cerr << \"Illegal Q\\n\";\n                exit(1);\n            }\n            board[cr.r][cr.c] = cr.hold;\n            cr.hold = -1;\n            return;\n        } else {\n            int nr = cr.r, nc = cr.c;\n            if (act == 'U') nr--;\n            if (act == 'D') nr++;\n            if (act == 'L') nc--;\n            if (act == 'R') nc++;\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                cerr << \"Illegal move out of board\\n\";\n                exit(1);\n            }\n            // With our strategy only large crane moves after small cranes are bombed.\n            // Large crane can move onto occupied-container cells even while holding.\n            cr.r = nr;\n            cr.c = nc;\n            return;\n        }\n    }\n\n    void step_dispatch() {\n        for (int r = 0; r < N; r++) {\n            if (board[r][4] != -1) {\n                int b = board[r][4];\n                board[r][4] = -1;\n                total_dispatched++;\n                dispatched[b] = true;\n                // We always try to send to correct gate\n            }\n        }\n    }\n\n    void solve() {\n        // init cranes\n        cranes[0] = Crane{0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = Crane{i, 0, -1, true, false};\n\n        int turn = 0;\n        while (total_dispatched < 25 && turn < 10000) {\n            // 1. spawn\n            step_spawn();\n\n            // 2. choose actions\n            array<char, N> act;\n            act.fill('.');\n\n            if (turn == 0) {\n                for (int i = 1; i < N; i++) act[i] = 'B';\n            }\n\n            if (plan.empty()) {\n                plan = choose_next_plan();\n            }\n            if (!plan.empty()) {\n                act[0] = plan.front();\n                plan.pop_front();\n            } else {\n                act[0] = '.';\n            }\n\n            // record output\n            for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n\n            // 2. execute actions\n            // Small cranes only do B at turn 0, otherwise .\n            // Large crane is the only moving crane, so collision issues are absent by construction.\n            for (int i = 0; i < N; i++) apply_action(i, act[i]);\n\n            // 3. dispatch\n            step_dispatch();\n\n            turn++;\n        }\n\n        // Safety fallback: if somehow unfinished, just idle (should not happen)\n        while (total_dispatched < 25 && (int)out[0].size() < 10000) {\n            step_spawn();\n            for (int i = 0; i < N; i++) out[i].push_back('.');\n            step_dispatch();\n        }\n\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    Solver solver;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> solver.A[i][j];\n        }\n    }\n    solver.solve();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing P = pair<int,int>;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> h(N, vector<int>(N));\n    ll base = 0;\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> h[i][j];\n            base += llabs(h[i][j]);\n        }\n    }\n\n    // A canonical Hamiltonian cycle for even N:\n    // top row all columns,\n    // then snake through rows 1..N-1 excluding column 0,\n    // then go up through column 0.\n    auto make_canonical_cycle = [&]() -> vector<P> {\n        vector<P> cyc;\n        cyc.reserve(N * N);\n\n        for (int c = 0; c < N; ++c) cyc.push_back({0, c});\n\n        for (int r = 1; r < N; ++r) {\n            if (r % 2 == 1) {\n                for (int c = N - 1; c >= 1; --c) cyc.push_back({r, c});\n            } else {\n                for (int c = 1; c < N; ++c) cyc.push_back({r, c});\n            }\n        }\n\n        for (int r = N - 1; r >= 1; --r) cyc.push_back({r, 0});\n\n        return cyc;\n    };\n\n    auto transform_point = [&](P p, int flip, int rot) -> P {\n        int r = p.first, c = p.second;\n        // optional mirror\n        if (flip) c = N - 1 - c;\n        // rotate rot times by 90 degrees\n        for (int k = 0; k < rot; ++k) {\n            int nr = c;\n            int nc = N - 1 - r;\n            r = nr;\n            c = nc;\n        }\n        return {r, c};\n    };\n\n    vector<P> base_cycle = make_canonical_cycle();\n    vector<vector<P>> candidates;\n\n    // 8 dihedral transforms * reverse/non-reverse\n    for (int flip = 0; flip < 2; ++flip) {\n        for (int rot = 0; rot < 4; ++rot) {\n            vector<P> cyc;\n            cyc.reserve(N * N);\n            for (auto p : base_cycle) cyc.push_back(transform_point(p, flip, rot));\n            candidates.push_back(cyc);\n\n            vector<P> rev = cyc;\n            reverse(rev.begin(), rev.end());\n            candidates.push_back(rev);\n        }\n    }\n\n    ll best_var_cost = (1LL << 62);\n    int best_id = -1;\n    int best_start = -1;\n\n    // Evaluate each cycle and each break point.\n    for (int id = 0; id < (int)candidates.size(); ++id) {\n        const auto &cyc = candidates[id];\n        int M = (int)cyc.size();\n\n        for (int s = 0; s < M; ++s) {\n            ll load = 0;\n            ll sum_loaded_move_cost = 0;\n            bool ok = true;\n\n            for (int t = 0; t < M; ++t) {\n                auto [r, c] = cyc[(s + t) % M];\n                load += h[r][c];\n                if (load < 0) {\n                    ok = false;\n                    break;\n                }\n                if (t < M - 1) sum_loaded_move_cost += load;\n            }\n\n            if (!ok || load != 0) continue;\n\n            auto [sr, sc] = cyc[s];\n            ll reposition = abs(sr - 0) + abs(sc - 0); // empty truck\n            ll move_steps = reposition + (M - 1);\n            ll var_cost = 100LL * move_steps + sum_loaded_move_cost;\n\n            if (var_cost < best_var_cost) {\n                best_var_cost = var_cost;\n                best_id = id;\n                best_start = s;\n            }\n        }\n    }\n\n    // Safety: there should always be at least one feasible start for each cycle.\n    if (best_id == -1) {\n        // Fallback: do nothing (should never happen)\n        return 0;\n    }\n\n    vector<P> path;\n    {\n        const auto &cyc = candidates[best_id];\n        int M = (int)cyc.size();\n        path.reserve(M);\n        for (int t = 0; t < M; ++t) path.push_back(cyc[(best_start + t) % M]);\n    }\n\n    vector<string> ans;\n    ans.reserve(2000);\n\n    int cr = 0, cc = 0;\n    auto push_move = [&](char ch) {\n        ans.emplace_back(1, ch);\n    };\n\n    auto move_to = [&](int tr, int tc) {\n        while (cr < tr) { push_move('D'); ++cr; }\n        while (cr > tr) { push_move('U'); --cr; }\n        while (cc < tc) { push_move('R'); ++cc; }\n        while (cc > tc) { push_move('L'); --cc; }\n    };\n\n    auto move_adj = [&](P from, P to) {\n        int r1 = from.first, c1 = from.second;\n        int r2 = to.first, c2 = to.second;\n        if (r2 == r1 + 1 && c2 == c1) push_move('D');\n        else if (r2 == r1 - 1 && c2 == c1) push_move('U');\n        else if (r2 == r1 && c2 == c1 + 1) push_move('R');\n        else if (r2 == r1 && c2 == c1 - 1) push_move('L');\n        else {\n            // should never happen\n            assert(false);\n        }\n        cr = r2;\n        cc = c2;\n    };\n\n    // Reposition empty truck to the chosen start.\n    move_to(path[0].first, path[0].second);\n\n    ll truck = 0;\n    for (int i = 0; i < (int)path.size(); ++i) {\n        auto [r, c] = path[i];\n        assert(cr == r && cc == c);\n\n        int v = h[r][c];\n        if (v > 0) {\n            ans.push_back(\"+\" + to_string(v));\n            truck += v;\n        } else if (v < 0) {\n            assert(truck >= -1LL * v);\n            ans.push_back(\"-\" + to_string(-v));\n            truck += v; // v is negative\n        }\n\n        if (i + 1 < (int)path.size()) {\n            move_adj(path[i], path[i + 1]);\n        }\n    }\n\n    assert(truck == 0);\n    assert((int)ans.size() <= 100000);\n\n    for (const string &s : ans) {\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { // [0, n)\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Solver {\n    int N, M, T, S;\n    vector<vector<int>> X;\n    vector<int> V;\n\n    vector<vector<int>> neigh;\n    vector<pair<int,int>> edges;\n    vector<int> posOrder;\n\n    XorShift64 rng;\n\n    void build_grid_info() {\n        int P = N * N;\n        neigh.assign(P, {});\n        edges.clear();\n\n        auto id = [&](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 p = id(r, c);\n                if (r + 1 < N) {\n                    int q = id(r + 1, c);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (c + 1 < N) {\n                    int q = id(r, c + 1);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n\n        vector<int> ps(P);\n        iota(ps.begin(), ps.end(), 0);\n\n        auto degree = [&](int p) { return (int)neigh[p].size(); };\n        auto dist2_center = [&](int p) {\n            int r = p / N, c = p % N;\n            double cr = (N - 1) / 2.0;\n            double cc = (N - 1) / 2.0;\n            double dr = r - cr;\n            double dc = c - cc;\n            return dr * dr + dc * dc;\n        };\n\n        sort(ps.begin(), ps.end(), [&](int a, int b) {\n            int da = degree(a), db = degree(b);\n            if (da != db) return da > db;\n            double xa = dist2_center(a), xb = dist2_center(b);\n            if (xa != xb) return xa < xb;\n            return a < b;\n        });\n\n        posOrder = ps;\n    }\n\n    bool read_seed_set() {\n        X.assign(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> X[i][j])) return false;\n            }\n        }\n        return true;\n    }\n\n    double arrangement_score(const vector<int>& perm,\n                             const vector<vector<double>>& pw) {\n        double sc = 0.0;\n        for (auto [u, v] : edges) sc += pw[perm[u]][perm[v]];\n        return sc;\n    }\n\n    double delta_swap(vector<int>& perm, int p, int q,\n                      const vector<vector<double>>& pw) {\n        if (p == q) return 0.0;\n\n        array<pair<int,int>, 8> aff{};\n        int cnt = 0;\n\n        auto add_edge = [&](int a, int b) {\n            if (a > b) swap(a, b);\n            for (int i = 0; i < cnt; i++) {\n                if (aff[i].first == a && aff[i].second == b) return;\n            }\n            aff[cnt++] = {a, b};\n        };\n\n        for (int nb : neigh[p]) add_edge(p, nb);\n        for (int nb : neigh[q]) add_edge(q, nb);\n\n        double oldv = 0.0, newv = 0.0;\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            oldv += pw[perm[a]][perm[b]];\n        }\n\n        swap(perm[p], perm[q]);\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            newv += pw[perm[a]][perm[b]];\n        }\n        swap(perm[p], perm[q]);\n\n        return newv - oldv;\n    }\n\n    vector<int> choose_seeds(int turn,\n                             const vector<double>& uniqBonus) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        double coverWeight = 0.9 * explore + 0.25;\n\n        vector<int> idx(S);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<char> used(S, 0);\n        vector<int> selected;\n\n        // Mandatory: a few best totals\n        int topKeep = 5;\n        for (int i = 0; i < min(topKeep, S); i++) {\n            int id = idx[i];\n            if (!used[id]) {\n                used[id] = 1;\n                selected.push_back(id);\n            }\n        }\n\n        // Mandatory: best seed for each criterion\n        for (int l = 0; l < M; l++) {\n            int bestId = 0;\n            for (int i = 1; i < S; i++) {\n                if (X[i][l] > X[bestId][l] ||\n                    (X[i][l] == X[bestId][l] && V[i] > V[bestId])) {\n                    bestId = i;\n                }\n            }\n            if (!used[bestId]) {\n                used[bestId] = 1;\n                selected.push_back(bestId);\n            }\n        }\n\n        vector<int> bestSel(M, 0);\n        for (int id : selected) {\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[id][l]);\n        }\n\n        while ((int)selected.size() < N * N) {\n            double bestGain = -1e100;\n            int bestId = -1;\n\n            for (int i = 0; i < S; i++) if (!used[i]) {\n                int cov = 0;\n                for (int l = 0; l < M; l++) {\n                    if (X[i][l] > bestSel[l]) cov += X[i][l] - bestSel[l];\n                }\n                double gain = (double)V[i]\n                            + coverWeight * cov\n                            + 0.5 * explore * uniqBonus[i];\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestId = i;\n                }\n            }\n\n            used[bestId] = 1;\n            selected.push_back(bestId);\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[bestId][l]);\n        }\n\n        return selected;\n    }\n\n    vector<int> optimize_layout(const vector<int>& selected,\n                                const vector<double>& uniqBonus,\n                                int turn) {\n        int P = N * N;\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        double uniqW = 1.5 * explore + 0.5;\n        double alpha = 0.55 * explore + 0.25; // blend toward coord-wise max early\n\n        vector<int> localToGlobal = selected;\n        vector<double> breeder(P);\n        for (int i = 0; i < P; i++) {\n            int g = localToGlobal[i];\n            breeder[i] = (double)V[g] + uniqW * uniqBonus[g];\n        }\n\n        vector<int> orderLocal(P);\n        iota(orderLocal.begin(), orderLocal.end(), 0);\n        sort(orderLocal.begin(), orderLocal.end(), [&](int a, int b) {\n            if (breeder[a] != breeder[b]) return breeder[a] > breeder[b];\n            int ga = localToGlobal[a], gb = localToGlobal[b];\n            if (V[ga] != V[gb]) return V[ga] > V[gb];\n            return ga < gb;\n        });\n\n        vector<vector<double>> pw(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            int a = localToGlobal[i];\n            for (int j = i + 1; j < P; j++) {\n                int b = localToGlobal[j];\n                int ub = 0;\n                for (int l = 0; l < M; l++) ub += max(X[a][l], X[b][l]);\n                double mean = 0.5 * (V[a] + V[b]);\n                double w = mean + alpha * (ub - mean);\n                pw[i][j] = pw[j][i] = w;\n            }\n        }\n\n        vector<int> perm(P, -1); // position -> local seed index\n        for (int k = 0; k < P; k++) perm[posOrder[k]] = orderLocal[k];\n\n        double cur = arrangement_score(perm, pw);\n\n        // Simulated annealing\n        const int ITER = 25000;\n        const double T0 = 25.0;\n        const double T1 = 0.2;\n\n        for (int it = 0; it < ITER; it++) {\n            int p = rng.next_int(P);\n            int q = rng.next_int(P);\n            if (p == q) continue;\n\n            double temp = T0 * pow(T1 / T0, (double)it / ITER);\n            double delta = delta_swap(perm, p, q, pw);\n\n            if (delta >= 0.0 || rng.next_double() < exp(delta / temp)) {\n                swap(perm[p], perm[q]);\n                cur += delta;\n            }\n        }\n\n        // Final hill climbing\n        for (int rep = 0; rep < 20; rep++) {\n            double bestDelta = 1e-12;\n            int bp = -1, bq = -1;\n            for (int p = 0; p < P; p++) {\n                for (int q = p + 1; q < P; q++) {\n                    double d = delta_swap(perm, p, q, pw);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n            if (bp == -1) break;\n            swap(perm[bp], perm[bq]);\n            cur += bestDelta;\n        }\n\n        vector<int> ans(P);\n        for (int p = 0; p < P; p++) ans[p] = localToGlobal[perm[p]];\n        return ans;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> T;\n        S = 2 * N * (N - 1);\n\n        build_grid_info();\n        if (!read_seed_set()) return;\n\n        for (int turn = 0; turn < T; turn++) {\n            V.assign(S, 0);\n            for (int i = 0; i < S; i++) {\n                for (int l = 0; l < M; l++) V[i] += X[i][l];\n            }\n\n            // Compute uniqueness bonus: if a seed is uniquely strong on a criterion,\n            // give it more importance so that it is preserved and placed well.\n            vector<double> uniqBonus(S, 0.0);\n            for (int l = 0; l < M; l++) {\n                int best = -1, second = -1, bestId = -1;\n                for (int i = 0; i < S; i++) {\n                    int val = X[i][l];\n                    if (val > best) {\n                        second = best;\n                        best = val;\n                        bestId = i;\n                    } else if (val > second) {\n                        second = val;\n                    }\n                }\n                if (bestId != -1 && second != -1) {\n                    uniqBonus[bestId] += (best - second);\n                }\n            }\n\n            vector<int> selected = choose_seeds(turn, uniqBonus);\n            vector<int> layout = optimize_layout(selected, uniqBonus, turn);\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    if (c) cout << ' ';\n                    cout << layout[r * N + c];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (!read_seed_set()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nlong long route_len_from_order(\n    const vector<int>& order,\n    const vector<int>& matchST,\n    const vector<Pt>& S,\n    const vector<Pt>& T\n) {\n    int D = (int)order.size();\n    if (D == 0) return 0;\n    long long res = 1; // first pickup at initial cell\n    int s0 = order[0];\n    res += manhattan(S[s0], T[matchST[s0]]);\n    for (int i = 1; i < D; i++) {\n        int prevs = order[i - 1];\n        int curs = order[i];\n        res += manhattan(T[matchST[prevs]], S[curs]);\n        res += manhattan(S[curs], T[matchST[curs]]);\n    }\n    return res;\n}\n\nvector<int> hungarian(const vector<vector<int>>& a) {\n    int n = (int)a.size();\n    if (n == 0) return {};\n    int m = n;\n    const int INF = 1e9;\n    vector<int> u(n + 1), v(m + 1), p(m + 1), way(m + 1);\n\n    for (int i = 1; i <= n; i++) {\n        p[0] = i;\n        int j0 = 0;\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n        do {\n            used[j0] = true;\n            int i0 = p[j0], delta = INF, j1 = 0;\n            for (int j = 1; j <= m; j++) {\n                if (used[j]) continue;\n                int cur = a[i0 - 1][j - 1] - u[i0] - v[j];\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\n            }\n            for (int j = 0; j <= m; j++) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            j0 = j1;\n        } while (p[j0] != 0);\n\n        do {\n            int j1 = way[j0];\n            p[j0] = p[j1];\n            j0 = j1;\n        } while (j0 != 0);\n    }\n\n    vector<int> ans(n, -1);\n    for (int j = 1; j <= m; j++) {\n        if (p[j] != 0) ans[p[j] - 1] = j - 1;\n    }\n    return ans;\n}\n\nstruct PairingResult {\n    vector<int> matchST; // source i -> target matchST[i]\n    vector<int> greedyOrder; // order of sources selected during pairing\n};\n\nPairingResult greedy_pairing_weighted(\n    int wc, int wp,\n    const vector<Pt>& S,\n    const vector<Pt>& T,\n    const vector<vector<int>>& distST\n) {\n    int D = (int)S.size();\n    vector<char> usedS(D, false), usedT(D, false);\n    vector<int> matchST(D, -1), order;\n    int prevT = -1;\n\n    for (int step = 0; step < D; step++) {\n        long long bestScore = (1LL << 60);\n        int bestAdd = INT_MAX;\n        int bestS = -1, bestT = -1;\n\n        for (int i = 0; i < D; i++) {\n            if (usedS[i]) continue;\n            int dcur = 0;\n            if (prevT != -1) dcur = manhattan(T[prevT], S[i]);\n            for (int j = 0; j < D; j++) {\n                if (usedT[j]) continue;\n                int dcar = distST[i][j];\n                long long score = 1LL * wc * dcur + 1LL * wp * dcar;\n                int actualAdd = dcur + dcar;\n                if (score < bestScore ||\n                    (score == bestScore && actualAdd < bestAdd) ||\n                    (score == bestScore && actualAdd == bestAdd && dcar < distST[bestS == -1 ? i : bestS][bestT == -1 ? j : bestT])) {\n                    bestScore = score;\n                    bestAdd = actualAdd;\n                    bestS = i;\n                    bestT = j;\n                }\n            }\n        }\n\n        usedS[bestS] = true;\n        usedT[bestT] = true;\n        matchST[bestS] = bestT;\n        order.push_back(bestS);\n        prevT = bestT;\n    }\n\n    return {matchST, order};\n}\n\nPairingResult greedy_pairing_nearest_source(\n    const vector<Pt>& S,\n    const vector<Pt>& T,\n    const vector<vector<int>>& distST\n) {\n    int D = (int)S.size();\n    vector<char> usedS(D, false), usedT(D, false);\n    vector<int> matchST(D, -1), order;\n    int prevT = -1;\n\n    for (int step = 0; step < D; step++) {\n        int bestS = -1;\n        if (prevT == -1) {\n            int bestD = INT_MAX, bestI = -1, bestJ = -1;\n            for (int i = 0; i < D; i++) if (!usedS[i]) {\n                for (int j = 0; j < D; j++) if (!usedT[j]) {\n                    if (distST[i][j] < bestD) {\n                        bestD = distST[i][j];\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n            bestS = bestI;\n            int bestT = bestJ;\n            usedS[bestS] = true;\n            usedT[bestT] = true;\n            matchST[bestS] = bestT;\n            order.push_back(bestS);\n            prevT = bestT;\n            continue;\n        } else {\n            int bestSourceDist = INT_MAX;\n            int bestNearestTarget = INT_MAX;\n            for (int i = 0; i < D; i++) if (!usedS[i]) {\n                int ds = manhattan(T[prevT], S[i]);\n                int nearT = INT_MAX;\n                for (int j = 0; j < D; j++) if (!usedT[j]) {\n                    nearT = min(nearT, distST[i][j]);\n                }\n                if (ds < bestSourceDist || (ds == bestSourceDist && nearT < bestNearestTarget)) {\n                    bestSourceDist = ds;\n                    bestNearestTarget = nearT;\n                    bestS = i;\n                }\n            }\n        }\n\n        int bestT = -1, bestD = INT_MAX;\n        for (int j = 0; j < D; j++) if (!usedT[j]) {\n            if (distST[bestS][j] < bestD) {\n                bestD = distST[bestS][j];\n                bestT = j;\n            }\n        }\n\n        usedS[bestS] = true;\n        usedT[bestT] = true;\n        matchST[bestS] = bestT;\n        order.push_back(bestS);\n        prevT = bestT;\n    }\n\n    return {matchST, order};\n}\n\nvector<int> build_order_cheapest_insertion(\n    const vector<int>& matchST,\n    const vector<Pt>& S,\n    const vector<Pt>& T\n) {\n    int D = (int)S.size();\n    if (D == 0) return {};\n    if (D == 1) return {0};\n\n    vector<vector<int>> C(D, vector<int>(D));\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            C[i][j] = manhattan(T[matchST[i]], S[j]);\n        }\n    }\n\n    int a = -1, b = -1, best = INT_MAX;\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            if (i == j) continue;\n            if (C[i][j] < best) {\n                best = C[i][j];\n                a = i;\n                b = j;\n            }\n        }\n    }\n\n    vector<int> seq = {a, b};\n    vector<char> used(D, false);\n    used[a] = used[b] = true;\n\n    while ((int)seq.size() < D) {\n        long long bestDelta = (1LL << 60);\n        int bestJob = -1, bestPos = -1;\n        int m = (int)seq.size();\n\n        for (int k = 0; k < D; k++) {\n            if (used[k]) continue;\n\n            // insert at front\n            {\n                long long delta = C[k][seq[0]];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestJob = k;\n                    bestPos = 0;\n                }\n            }\n            // insert at end\n            {\n                long long delta = C[seq[m - 1]][k];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestJob = k;\n                    bestPos = m;\n                }\n            }\n            // insert in middle\n            for (int pos = 1; pos < m; pos++) {\n                long long delta = 1LL * C[seq[pos - 1]][k] + C[k][seq[pos]] - C[seq[pos - 1]][seq[pos]];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestJob = k;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        seq.insert(seq.begin() + bestPos, bestJob);\n        used[bestJob] = true;\n    }\n\n    // Relocate local search\n    for (int pass = 0; pass < 10; pass++) {\n        long long bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        int n = (int)seq.size();\n\n        for (int i = 0; i < n; i++) {\n            int x = seq[i];\n            long long removeDelta = 0;\n            if (i > 0) removeDelta -= C[seq[i - 1]][x];\n            if (i + 1 < n) removeDelta -= C[x][seq[i + 1]];\n            if (i > 0 && i + 1 < n) removeDelta += C[seq[i - 1]][seq[i + 1]];\n\n            int m = n - 1;\n            auto getShort = [&](int pos) -> int {\n                return seq[(pos < i) ? pos : pos + 1];\n            };\n\n            for (int j = 0; j <= m; j++) {\n                if (j == i) continue; // same position after removal\n\n                long long delta = removeDelta;\n                if (m == 0) {\n                    // nothing\n                } else if (j == 0) {\n                    delta += C[x][getShort(0)];\n                } else if (j == m) {\n                    delta += C[getShort(m - 1)][x];\n                } else {\n                    int p = getShort(j - 1);\n                    int q = getShort(j);\n                    delta += 1LL * C[p][x] + C[x][q] - C[p][q];\n                }\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        int x = seq[bestI];\n        seq.erase(seq.begin() + bestI);\n        seq.insert(seq.begin() + bestJ, x);\n    }\n\n    return seq;\n}\n\nvector<string> build_operations(\n    const vector<int>& order,\n    const vector<int>& matchST,\n    const vector<Pt>& S,\n    const vector<Pt>& T\n) {\n    vector<string> ops;\n    if (order.empty()) return ops;\n\n    auto push_move = [&](char mv, bool pickplace) {\n        string s = \"..\";\n        s[0] = mv;\n        if (pickplace) s[1] = 'P';\n        ops.push_back(s);\n    };\n\n    auto move_path = [&](Pt& cur, const Pt& to, bool actionOnArrival) {\n        int dx = to.x - cur.x;\n        int dy = to.y - cur.y;\n        vector<char> path;\n        if (dx > 0) for (int k = 0; k < dx; k++) path.push_back('D');\n        if (dx < 0) for (int k = 0; k < -dx; k++) path.push_back('U');\n        if (dy > 0) for (int k = 0; k < dy; k++) path.push_back('R');\n        if (dy < 0) for (int k = 0; k < -dy; k++) path.push_back('L');\n\n        if (path.empty()) {\n            if (actionOnArrival) push_move('.', true);\n        } else {\n            for (int i = 0; i < (int)path.size(); i++) {\n                bool act = actionOnArrival && (i + 1 == (int)path.size());\n                push_move(path[i], act);\n            }\n        }\n        cur = to;\n    };\n\n    Pt cur = S[order[0]];\n    // first pickup\n    ops.push_back(\".P\");\n\n    for (int idx = 0; idx < (int)order.size(); idx++) {\n        int s = order[idx];\n        int t = matchST[s];\n\n        if (idx > 0) {\n            move_path(cur, S[s], true);   // arrive source and pick\n        }\n        move_path(cur, T[t], true);       // arrive target and drop\n    }\n\n    return ops;\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<Pt> S, T;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') S.push_back({i, j});\n            if (s[i][j] == '0' && t[i][j] == '1') T.push_back({i, j});\n        }\n    }\n\n    int D = (int)S.size();\n    vector<vector<int>> distST(D, vector<int>(D, 0));\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            distST[i][j] = manhattan(S[i], T[j]);\n        }\n    }\n\n    long long bestLen = (1LL << 60);\n    vector<int> bestOrder, bestMatch;\n\n    auto try_candidate = [&](const vector<int>& order, const vector<int>& matchST) {\n        long long len = route_len_from_order(order, matchST, S, T);\n        if (len < bestLen) {\n            bestLen = len;\n            bestOrder = order;\n            bestMatch = matchST;\n        }\n    };\n\n    if (D > 0) {\n        // Greedy pairings with different weights\n        vector<pair<int,int>> weights = {\n            {1, 1},\n            {1, 2},\n            {2, 1}\n        };\n\n        for (auto [wc, wp] : weights) {\n            auto pr = greedy_pairing_weighted(wc, wp, S, T, distST);\n            try_candidate(pr.greedyOrder, pr.matchST);\n\n            auto ord2 = build_order_cheapest_insertion(pr.matchST, S, T);\n            try_candidate(ord2, pr.matchST);\n        }\n\n        // Another greedy\n        {\n            auto pr = greedy_pairing_nearest_source(S, T, distST);\n            try_candidate(pr.greedyOrder, pr.matchST);\n\n            auto ord2 = build_order_cheapest_insertion(pr.matchST, S, T);\n            try_candidate(ord2, pr.matchST);\n        }\n\n        // Hungarian matching + route optimization\n        {\n            auto match = hungarian(distST);\n            auto ord = build_order_cheapest_insertion(match, S, T);\n            try_candidate(ord, match);\n        }\n    }\n\n    // Output arm design: single-vertex tree\n    cout << 1 << '\\n';\n    if (D == 0) {\n        cout << 0 << ' ' << 0 << '\\n';\n        return 0;\n    } else {\n        Pt start = S[bestOrder[0]];\n        cout << start.x << ' ' << start.y << '\\n';\n    }\n\n    auto ops = build_operations(bestOrder, bestMatch, S, T);\n    for (auto& op : ops) cout << op << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Point {\n    int x, y;\n};\n\nstruct WPoint {\n    int x, y;\n    int w; // +1 for mackerel, -1 for sardine\n};\n\nstruct PolyInfo {\n    vector<Point> poly;\n    int unit_perimeter = 0; // in grid-edge count\n    bool ok = false;\n};\n\nstatic inline uint64_t pack_xy(int x, int y) {\n    return (uint64_t(uint32_t(x)) << 32) | uint32_t(y);\n}\n\nstatic inline bool on_segment(const Point& p, const Point& a, const Point& b) {\n    if (a.x == b.x) {\n        if (p.x != a.x) return false;\n        return min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);\n    } else if (a.y == b.y) {\n        if (p.y != a.y) return false;\n        return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x);\n    }\n    return false;\n}\n\nstatic bool inside_polygon_inclusive(const Point& p, const vector<Point>& poly) {\n    bool in = false;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        Point a = poly[i];\n        Point b = poly[(i + 1) % n];\n\n        if (on_segment(p, a, b)) return true;\n\n        // Ray casting to +x direction; only vertical edges matter\n        if (a.x == b.x) {\n            if (a.y > b.y) swap(a, b);\n            // [a.y, b.y)\n            if (a.y <= p.y && p.y < b.y && p.x < a.x) {\n                in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int exact_diff(const vector<Point>& poly, const vector<WPoint>& pts) {\n    if (poly.empty()) return INT_MIN / 4;\n\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    for (auto &q : poly) {\n        minx = min(minx, q.x);\n        maxx = max(maxx, q.x);\n        miny = min(miny, q.y);\n        maxy = max(maxy, q.y);\n    }\n\n    int diff = 0;\n    for (auto &pt : pts) {\n        if (pt.x < minx || pt.x > maxx || pt.y < miny || pt.y > maxy) continue;\n        if (inside_polygon_inclusive(Point{pt.x, pt.y}, poly)) diff += pt.w;\n    }\n    return diff;\n}\n\nstatic vector<Point> fallback_polygon(const unordered_set<uint64_t>& occ) {\n    for (int x = 0; x <= 200; x++) {\n        for (int y = 0; y <= 200; y++) {\n            if (!occ.count(pack_xy(x, y)) &&\n                !occ.count(pack_xy(x + 1, y)) &&\n                !occ.count(pack_xy(x, y + 1)) &&\n                !occ.count(pack_xy(x + 1, y + 1))) {\n                return {\n                    {x, y},\n                    {x + 1, y},\n                    {x + 1, y + 1},\n                    {x, y + 1}\n                };\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nstatic void fill_holes(vector<char>& sel, int W, int H) {\n    vector<char> vis(W * H, 0);\n    queue<int> q;\n\n    auto try_push = [&](int x, int y) {\n        int id = y * W + x;\n        if (!sel[id] && !vis[id]) {\n            vis[id] = 1;\n            q.push(id);\n        }\n    };\n\n    for (int x = 0; x < W; x++) {\n        try_push(x, 0);\n        try_push(x, H - 1);\n    }\n    for (int y = 0; y < H; y++) {\n        try_push(0, y);\n        try_push(W - 1, y);\n    }\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir];\n            int ny = y + dy[dir];\n            if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n            int nid = ny * W + nx;\n            if (!sel[nid] && !vis[nid]) {\n                vis[nid] = 1;\n                q.push(nid);\n            }\n        }\n    }\n\n    for (int i = 0; i < W * H; i++) {\n        if (!sel[i] && !vis[i]) sel[i] = 1; // hole\n    }\n}\n\nstruct Component {\n    vector<int> cells;\n    int approx = 0;\n};\n\nstatic vector<Component> get_components(const vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    vector<char> vis(W * H, 0);\n    vector<Component> comps;\n    queue<int> q;\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int s = 0; s < W * H; s++) {\n        if (!sel[s] || vis[s]) continue;\n        vis[s] = 1;\n        q.push(s);\n\n        Component comp;\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            comp.cells.push_back(v);\n            comp.approx += cell_w[v];\n\n            int x = v % W, y = v / W;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir];\n                int ny = y + dy[dir];\n                if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n                int nid = ny * W + nx;\n                if (sel[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        comps.push_back(move(comp));\n    }\n\n    sort(comps.begin(), comps.end(), [](const Component& a, const Component& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        return a.cells.size() > b.cells.size();\n    });\n    return comps;\n}\n\nstatic PolyInfo build_polygon_from_component(const vector<char>& comp_sel, int W, int H, int S) {\n    PolyInfo res;\n    int GW = W + 1;\n    int GV = (W + 1) * (H + 1);\n    vector<int> nxt(GV, -1);\n    int edge_cnt = 0;\n\n    auto vid = [&](int x, int y) -> int {\n        return y * GW + x;\n    };\n    auto add_edge = [&](int x1, int y1, int x2, int y2) -> bool {\n        int a = vid(x1, y1);\n        int b = vid(x2, y2);\n        if (nxt[a] != -1) return false;\n        nxt[a] = b;\n        edge_cnt++;\n        return true;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int id = y * W + x;\n            if (!comp_sel[id]) continue;\n\n            // CCW boundary around occupied cells\n            if (y == 0 || !comp_sel[(y - 1) * W + x]) {\n                if (!add_edge(x, y, x + 1, y)) return res;\n            }\n            if (x == W - 1 || !comp_sel[y * W + (x + 1)]) {\n                if (!add_edge(x + 1, y, x + 1, y + 1)) return res;\n            }\n            if (y == H - 1 || !comp_sel[(y + 1) * W + x]) {\n                if (!add_edge(x + 1, y + 1, x, y + 1)) return res;\n            }\n            if (x == 0 || !comp_sel[y * W + (x - 1)]) {\n                if (!add_edge(x, y + 1, x, y)) return res;\n            }\n        }\n    }\n\n    if (edge_cnt == 0) return res;\n\n    int start = -1;\n    for (int i = 0; i < GV; i++) {\n        if (nxt[i] != -1) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return res;\n\n    vector<int> cyc;\n    int cur = start;\n    for (int step = 0; step <= edge_cnt + 5; step++) {\n        cyc.push_back(cur);\n        cur = nxt[cur];\n        if (cur == -1) return res;\n        if (cur == start) break;\n    }\n    if (cur != start) return res;\n\n    if ((int)cyc.size() != edge_cnt) {\n        // Multiple cycles / broken boundary\n        return res;\n    }\n\n    auto dec = [&](int v) -> pair<int,int> {\n        return {v % GW, v / GW};\n    };\n    auto dir = [&](int a, int b) -> pair<int,int> {\n        auto [x1, y1] = dec(a);\n        auto [x2, y2] = dec(b);\n        return {(x2 > x1) - (x2 < x1), (y2 > y1) - (y2 < y1)};\n    };\n\n    vector<Point> poly;\n    int n = (int)cyc.size();\n    for (int i = 0; i < n; i++) {\n        int pv = cyc[(i - 1 + n) % n];\n        int cv = cyc[i];\n        int nv = cyc[(i + 1) % n];\n        if (dir(pv, cv) != dir(cv, nv)) {\n            auto [x, y] = dec(cv);\n            poly.push_back(Point{x * S, y * S});\n        }\n    }\n\n    if ((int)poly.size() < 4) return res;\n    res.poly = move(poly);\n    res.unit_perimeter = edge_cnt;\n    res.ok = true;\n    return res;\n}\n\nstatic vector<char> solve_selection_by_cut(const vector<int>& cell_w, int W, int H, int lambda) {\n    int V = W * H + 2;\n    int S = W * H;\n    int T = W * H + 1;\n\n    if (lambda == 0) {\n        vector<char> sel(W * H, 0);\n        for (int i = 0; i < W * H; i++) {\n            if (cell_w[i] > 0) sel[i] = 1;\n        }\n        return sel;\n    }\n\n    mf_graph<int> g(V);\n\n    auto id = [&](int x, int y) -> int {\n        return y * W + x;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int outside_sides = 0;\n            if (x == 0) outside_sides++;\n            if (x == W - 1) outside_sides++;\n            if (y == 0) outside_sides++;\n            if (y == H - 1) outside_sides++;\n\n            int u = cell_w[v] - lambda * outside_sides;\n            if (u >= 0) g.add_edge(S, v, u);\n            else g.add_edge(v, T, -u);\n\n            if (x + 1 < W) {\n                int to = id(x + 1, y);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n            if (y + 1 < H) {\n                int to = id(x, y + 1);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n        }\n    }\n\n    g.flow(S, T);\n    auto cut = g.min_cut(S);\n\n    vector<char> sel(W * H, 0);\n    for (int i = 0; i < W * H; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<WPoint> pts;\n    pts.reserve(2 * N);\n    unordered_set<uint64_t> occ;\n    occ.reserve(2 * N * 2);\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, +1});\n        occ.insert(pack_xy(x, y));\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, -1});\n        occ.insert(pack_xy(x, y));\n    }\n\n    vector<Point> best_poly = fallback_polygon(occ);\n    int best_diff = exact_diff(best_poly, pts);\n\n    const vector<int> cell_sizes = {1000, 625, 500};\n    const vector<int> lambdas = {0, 1, 2, 4, 8};\n\n    for (int cell_size : cell_sizes) {\n        int W = 100000 / cell_size;\n        int H = W;\n\n        vector<int> cell_w(W * H, 0);\n        for (auto &p : pts) {\n            int gx = min(p.x / cell_size, W - 1);\n            int gy = min(p.y / cell_size, H - 1);\n            cell_w[gy * W + gx] += p.w;\n        }\n\n        for (int lambda : lambdas) {\n            vector<char> sel = solve_selection_by_cut(cell_w, W, H, lambda);\n\n            bool any = false;\n            for (char c : sel) if (c) { any = true; break; }\n            if (!any) continue;\n\n            fill_holes(sel, W, H);\n            auto comps = get_components(sel, cell_w, W, H);\n            if (comps.empty()) continue;\n\n            int K = (lambda == 0 ? 2 : 4);\n            K = min(K, (int)comps.size());\n\n            for (int ci = 0; ci < K; ci++) {\n                vector<char> comp_sel(W * H, 0);\n                for (int v : comps[ci].cells) comp_sel[v] = 1;\n\n                PolyInfo info = build_polygon_from_component(comp_sel, W, H, cell_size);\n                if (!info.ok) continue;\n\n                if ((int)info.poly.size() > 1000) continue;\n                long long peri = 1LL * info.unit_perimeter * cell_size;\n                if (peri > 400000LL) continue;\n\n                int diff = exact_diff(info.poly, pts);\n                if (diff > best_diff) {\n                    best_diff = diff;\n                    best_poly = move(info.poly);\n                }\n            }\n        }\n    }\n\n    cout << best_poly.size() << '\\n';\n    for (auto &p : best_poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing ld = long double;\n\nstruct Op {\n    int p, r;\n    char d;\n    int b;\n};\n\nstruct Placed {\n    ll x = 0, y = 0, w = 0, h = 0;\n    bool used = false;\n};\n\nstruct Candidate {\n    ll estW = 0, estH = 0, est = 0;\n    bool isRow = true;\n    int anchorStrategy = 0;\n    vector<Op> ops;\n    string sig;\n};\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nint N, T, sigma_;\nvector<ll> obsW, obsH;\n\nbool overlap1D(ll l1, ll r1, ll l2, ll r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nvoid place_one(int p, int r, char d, int b, vector<Placed>& placed, ll& W, ll& H) {\n    ll w = (r == 0 ? obsW[p] : obsH[p]);\n    ll h = (r == 0 ? obsH[p] : obsW[p]);\n\n    ll x = 0, y = 0;\n    if (d == 'U') {\n        x = (b == -1 ? 0 : placed[b].x + placed[b].w);\n        y = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(x, x + w, placed[i].x, placed[i].x + placed[i].w)) {\n                y = max(y, placed[i].y + placed[i].h);\n            }\n        }\n    } else { // 'L'\n        y = (b == -1 ? 0 : placed[b].y + placed[b].h);\n        x = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(y, y + h, placed[i].y, placed[i].y + placed[i].h)) {\n                x = max(x, placed[i].x + placed[i].w);\n            }\n        }\n    }\n\n    placed[p] = {x, y, w, h, true};\n    W = max(W, x + w);\n    H = max(H, y + h);\n}\n\nvector<pair<int,int>> partition_strip(const vector<ll>& primary, const vector<ll>& secondary, ll cap) {\n    vector<ll> dp(N + 1, INF64);\n    vector<int> cnt(N + 1, INT_MAX);\n    vector<int> prv(N + 1, -1);\n    dp[0] = 0;\n    cnt[0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        if (dp[i] >= INF64 / 2) continue;\n        ll sumP = 0;\n        ll mxS = 0;\n        for (int j = i; j < N; j++) {\n            sumP += primary[j];\n            if (sumP > cap) break;\n            mxS = max(mxS, secondary[j]);\n\n            ll ndp = dp[i] + mxS;\n            int ncnt = cnt[i] + 1;\n            if (ndp < dp[j + 1] || (ndp == dp[j + 1] && ncnt < cnt[j + 1])) {\n                dp[j + 1] = ndp;\n                cnt[j + 1] = ncnt;\n                prv[j + 1] = i;\n            }\n        }\n    }\n\n    if (prv[N] == -1) return {};\n\n    vector<pair<int,int>> segs_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = prv[cur];\n        if (p < 0) return {};\n        segs_rev.push_back({p, cur});\n        cur = p;\n    }\n    reverse(segs_rev.begin(), segs_rev.end());\n    return segs_rev;\n}\n\nstring make_signature(bool isRow, int strategy, const vector<int>& rot, const vector<pair<int,int>>& segs) {\n    string s;\n    s.reserve(2 + N + 1 + N);\n    s.push_back(isRow ? 'R' : 'C');\n    s.push_back(char('0' + strategy));\n    for (int i = 0; i < N; i++) s.push_back(char('0' + rot[i]));\n    s.push_back('|');\n    vector<char> br(N, '0');\n    for (auto [l, r] : segs) br[r - 1] = '1';\n    for (int i = 0; i < N; i++) s.push_back(br[i]);\n    return s;\n}\n\nCandidate build_row_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy) {\n    Candidate c;\n    c.isRow = true;\n    c.anchorStrategy = strategy;\n    c.sig = make_signature(true, strategy, rot, segs);\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto bottom = [&](int idx) -> ll {\n        return placed[idx].y + placed[idx].h;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'U', -1});\n            place_one(l, rot[l], 'U', -1, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'L', b});\n            place_one(l, rot[l], 'L', b, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'U', i - 1});\n            place_one(i, rot[i], 'U', i - 1, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (bottom(i) > bottom(prevMax)) prevMax = i;\n            if (bottom(i) < bottom(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || bottom(prevMax) > bottom(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || bottom(prevMin) < bottom(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    return c;\n}\n\nCandidate build_col_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy) {\n    Candidate c;\n    c.isRow = false;\n    c.anchorStrategy = strategy;\n    c.sig = make_signature(false, strategy, rot, segs);\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto right = [&](int idx) -> ll {\n        return placed[idx].x + placed[idx].w;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'L', -1});\n            place_one(l, rot[l], 'L', -1, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'U', b});\n            place_one(l, rot[l], 'U', b, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'L', i - 1});\n            place_one(i, rot[i], 'L', i - 1, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (right(i) > right(prevMax)) prevMax = i;\n            if (right(i) < right(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || right(prevMax) > right(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || right(prevMin) < right(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    return c;\n}\n\nvector<ll> generate_caps(const vector<ll>& primary, const vector<ll>& secondary) {\n    ll total = 0, mx = 0;\n    ld area = 0;\n    for (int i = 0; i < N; i++) {\n        total += primary[i];\n        mx = max(mx, primary[i]);\n        area += (ld)primary[i] * (ld)secondary[i];\n    }\n\n    vector<ll> vals;\n    vals.push_back(mx);\n\n    static const ld mults1[] = {0.72L, 0.85L, 1.00L, 1.15L, 1.35L};\n    int K = min(N, 16);\n    for (int k = 1; k <= K; k++) {\n        ld base = (ld)total / (ld)k;\n        for (ld m : mults1) {\n            ll v = (ll)llround(base * m);\n            vals.push_back(max(mx, v));\n        }\n    }\n\n    ld sq = sqrt(area);\n    static const ld mults2[] = {0.55L, 0.70L, 0.85L, 1.00L, 1.20L, 1.45L, 1.80L};\n    for (ld m : mults2) {\n        ll v = (ll)llround(sq * m);\n        vals.push_back(max(mx, v));\n    }\n\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end()), vals.end());\n\n    // Downsample if too many.\n    if ((int)vals.size() > 40) {\n        vector<ll> sampled;\n        sampled.reserve(40);\n        for (int i = 0; i < 40; i++) {\n            int idx = (int)((ld)i * (ld)(vals.size() - 1) / 39.0L);\n            if (sampled.empty() || sampled.back() != vals[idx]) sampled.push_back(vals[idx]);\n        }\n        vals = move(sampled);\n    }\n\n    return vals;\n}\n\nvector<vector<int>> generate_rotation_modes() {\n    vector<vector<int>> modes;\n    unordered_set<string> seen;\n\n    auto add_mode = [&](const vector<int>& rot) {\n        string s;\n        s.reserve(N);\n        for (int b : rot) s.push_back(char('0' + b));\n        if (seen.insert(s).second) modes.push_back(rot);\n    };\n\n    vector<int> all0(N, 0), all1(N, 1), minW(N), minH(N);\n    for (int i = 0; i < N; i++) {\n        minW[i] = (obsW[i] <= obsH[i] ? 0 : 1);\n        minH[i] = (obsH[i] <= obsW[i] ? 0 : 1);\n    }\n\n    add_mode(all0);\n    add_mode(all1);\n    add_mode(minW);\n    add_mode(minH);\n\n    vector<ll> mxs(N);\n    for (int i = 0; i < N; i++) mxs[i] = max(obsW[i], obsH[i]);\n    vector<ll> sortedMx = mxs;\n    sort(sortedMx.begin(), sortedMx.end());\n    ll th1 = sortedMx[N / 2];\n    ll th2 = sortedMx[(3 * N) / 4];\n\n    vector<int> hy1(N), hy2(N), hy3(N);\n    for (int i = 0; i < N; i++) {\n        hy1[i] = (mxs[i] >= th1 ? minW[i] : minH[i]);\n        hy2[i] = (mxs[i] >= th2 ? minW[i] : minH[i]);\n        hy3[i] = (mxs[i] >= th1 ? minH[i] : minW[i]);\n    }\n    add_mode(hy1);\n    add_mode(hy2);\n    add_mode(hy3);\n\n    ll near_thr = 2LL * sigma_;\n    vector<vector<int>> bases = {minW, minH, hy1, hy2};\n\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int seed = 0; seed < 2; seed++) {\n            vector<int> rot = bases[bi];\n            mt19937 rng(1234567 + 1009 * bi + seed);\n            for (int i = 0; i < N; i++) {\n                if (llabs(obsW[i] - obsH[i]) <= near_thr) {\n                    if (rng() & 1) rot[i] ^= 1;\n                }\n            }\n            add_mode(rot);\n        }\n    }\n\n    return modes;\n}\n\nvector<Candidate> generate_candidates() {\n    vector<Candidate> cands;\n    unordered_set<string> usedSig;\n\n    auto add_candidate = [&](Candidate&& c) {\n        if ((int)c.ops.size() != N) return;\n        if (usedSig.insert(c.sig).second) {\n            cands.push_back(move(c));\n        }\n    };\n\n    auto rotModes = generate_rotation_modes();\n\n    for (const auto& rot : rotModes) {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = (rot[i] == 0 ? obsW[i] : obsH[i]);\n            h[i] = (rot[i] == 0 ? obsH[i] : obsW[i]);\n        }\n\n        // Row-based packings.\n        {\n            auto caps = generate_caps(w, h);\n            for (ll cap : caps) {\n                auto segs = partition_strip(w, h, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_row_candidate(segs, rot, strat));\n                }\n            }\n        }\n\n        // Column-based packings.\n        {\n            auto caps = generate_caps(h, w);\n            for (ll cap : caps) {\n                auto segs = partition_strip(h, w, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_col_candidate(segs, rot, strat));\n                }\n            }\n        }\n    }\n\n    if (cands.empty()) {\n        // Fallback: single row, original orientation.\n        vector<int> rot(N, 0);\n        vector<pair<int,int>> segs = {{0, N}};\n        add_candidate(build_row_candidate(segs, rot, 0));\n        add_candidate(build_col_candidate(segs, rot, 0));\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.est != b.est) return a.est < b.est;\n        if (a.isRow != b.isRow) return a.isRow > b.isRow;\n        return a.sig < b.sig;\n    });\n\n    return cands;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_;\n    obsW.resize(N);\n    obsH.resize(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    vector<Candidate> candidates = generate_candidates();\n    if (candidates.empty()) return 0;\n\n    vector<char> used(candidates.size(), 0);\n    int firstChosen = -1;\n\n    ld sumEstW = 0, sumEstH = 0;\n    ld sumMeasW = 0, sumMeasH = 0;\n    const ld prior = 1e6L;\n\n    auto pick_best_adjusted = [&](bool forceOppositeType, bool oppositeType) -> int {\n        ld scaleW = (sumMeasW + prior) / (sumEstW + prior);\n        ld scaleH = (sumMeasH + prior) / (sumEstH + prior);\n\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            if (forceOppositeType && candidates[i].isRow != oppositeType) continue;\n            ld sc = scaleW * (ld)candidates[i].estW + scaleH * (ld)candidates[i].estH;\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    auto pick_best_raw = [&]() -> int {\n        int best = -1;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            if (best == -1 || candidates[i].est < candidates[best].est) best = i;\n        }\n        return best;\n    };\n\n    for (int turn = 0; turn < T; turn++) {\n        int idx = -1;\n\n        if (turn == 0) {\n            idx = pick_best_raw();\n            if (idx == -1) idx = 0;\n            firstChosen = idx;\n        } else if (turn == 1 && firstChosen != -1) {\n            bool wantOpposite = !candidates[firstChosen].isRow;\n            idx = pick_best_adjusted(true, wantOpposite);\n            if (idx == -1) idx = pick_best_adjusted(false, false);\n        } else {\n            idx = pick_best_adjusted(false, false);\n        }\n\n        if (idx == -1) idx = 0;\n        used[idx] = 1;\n        const auto& cand = candidates[idx];\n\n        cout << cand.ops.size() << '\\n';\n        for (const auto& op : cand.ops) {\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        ll measW, measH;\n        if (!(cin >> measW >> measH)) return 0;\n\n        sumEstW += (ld)cand.estW;\n        sumEstH += (ld)cand.estH;\n        sumMeasW += (ld)measW;\n        sumMeasH += (ld)measH;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> X, Y;\n\n    mt19937 rng{123456789};\n\n    chrono::steady_clock::time_point start_time;\n    double TL = 1.85; // safety margin\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    struct Info {\n        vector<int> depth, tin, tout, subH;\n        vector<long long> subA;\n        long long score = 0;\n    };\n\n    Info build_info(const vector<int>& parent) {\n        vector<vector<int>> children(N);\n        for (int v = 0; v < N; v++) {\n            if (parent[v] != -1) children[parent[v]].push_back(v);\n        }\n\n        Info info;\n        info.depth.assign(N, 0);\n        info.tin.assign(N, 0);\n        info.tout.assign(N, 0);\n        info.subH.assign(N, 0);\n        info.subA.assign(N, 0);\n        info.score = 0;\n\n        int timer = 0;\n\n        auto dfs = [&](auto&& self, int v) -> void {\n            info.tin[v] = timer++;\n            info.subA[v] = A[v];\n            info.subH[v] = 0;\n            info.score += 1LL * (info.depth[v] + 1) * A[v];\n\n            for (int c : children[v]) {\n                info.depth[c] = info.depth[v] + 1;\n                self(self, c);\n                info.subA[v] += info.subA[c];\n                info.subH[v] = max(info.subH[v], info.subH[c] + 1);\n            }\n            info.tout[v] = timer;\n        };\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                info.depth[v] = 0;\n                dfs(dfs, v);\n            }\n        }\n        return info;\n    }\n\n    static bool is_ancestor(const Info& info, int a, int b) {\n        return info.tin[a] <= info.tin[b] && info.tout[b] <= info.tout[a];\n    }\n\n    long long improve(vector<int>& parent) {\n        long long last_score = -1;\n\n        while (elapsed() < TL) {\n            Info info = build_info(parent);\n            last_score = info.score;\n\n            long long best_gain = 0;\n            int best_u = -1, best_v = -1;\n            int best_new_depth = -1;\n            long long best_subA = -1;\n\n            auto eval_move = [&](int u, int v) {\n                // move subtree rooted at v under u\n                if (parent[v] == u) return;\n                if (is_ancestor(info, v, u)) return; // would create cycle\n                if (info.depth[u] >= H) return;\n\n                int nd = info.depth[u] + 1;\n                if (nd <= info.depth[v]) return;\n                if (nd + info.subH[v] > H) return;\n\n                long long gain = 1LL * (nd - info.depth[v]) * info.subA[v];\n                if (gain > best_gain ||\n                    (gain == best_gain && nd > best_new_depth) ||\n                    (gain == best_gain && nd == best_new_depth && info.subA[v] > best_subA)) {\n                    best_gain = gain;\n                    best_u = u;\n                    best_v = v;\n                    best_new_depth = nd;\n                    best_subA = info.subA[v];\n                }\n            };\n\n            for (auto [a, b] : edges) {\n                eval_move(a, b);\n                eval_move(b, a);\n            }\n\n            if (best_gain <= 0) break;\n            parent[best_v] = best_u;\n        }\n\n        if (last_score == -1) last_score = build_info(parent).score;\n        return last_score;\n    }\n\n    vector<int> build_by_key(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n\n        vector<int> parent(N, -1), depth(N, 0);\n        vector<char> used(N, 0);\n\n        for (int v : ord) {\n            int best_p = -1;\n            int best_d = -1;\n\n            for (int u : g[v]) {\n                if (!used[u]) continue;\n                if (depth[u] >= H) continue;\n                if (depth[u] > best_d) {\n                    best_d = depth[u];\n                    best_p = u;\n                } else if (depth[u] == best_d && best_p != -1 && A[u] < A[best_p]) {\n                    best_p = u;\n                }\n            }\n\n            if (best_p != -1) {\n                parent[v] = best_p;\n                depth[v] = depth[best_p] + 1;\n            } else {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n            used[v] = 1;\n        }\n        return parent;\n    }\n\n    double rnd01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    vector<int> make_initial(int mode) {\n        // mode 0: all roots\n        if (mode == 0) {\n            return vector<int>(N, -1);\n        }\n\n        vector<double> key(N, 0.0);\n\n        if (mode == 1) {\n            // beauty ascending (low beauty tends to be shallow/internal)\n            for (int v = 0; v < N; v++) {\n                key[v] = 20.0 * A[v] + 0.01 * X[v] + 0.013 * Y[v] + 1e-6 * rnd01();\n            }\n            return build_by_key(key);\n        }\n\n        if (mode == 2) {\n            // radial + beauty\n            for (int v = 0; v < N; v++) {\n                double dx = X[v] - 500.0;\n                double dy = Y[v] - 500.0;\n                double r = sqrt(dx * dx + dy * dy);\n                key[v] = r + 4.0 * A[v] + 1e-6 * rnd01();\n            }\n            return build_by_key(key);\n        }\n\n        // random projection + beauty bias\n        double theta = uniform_real_distribution<double>(0.0, 2.0 * acos(-1.0))(rng);\n        double c = cos(theta), s = sin(theta);\n        static const int alphas[5] = {-6, -3, 0, 3, 6};\n        int alpha = alphas[rng() % 5];\n\n        for (int v = 0; v < N; v++) {\n            double proj = X[v] * c + Y[v] * s;\n            key[v] = proj + alpha * A[v] + 1e-6 * rnd01();\n        }\n        return build_by_key(key);\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            edges[i] = {u, v};\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        X.resize(N);\n        Y.resize(N);\n        for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n        start_time = chrono::steady_clock::now();\n\n        vector<int> best_parent(N, -1);\n        long long best_score = -1;\n\n        // deterministic starts\n        for (int mode = 0; mode <= 2; mode++) {\n            if (elapsed() >= TL) break;\n            vector<int> cur = make_initial(mode);\n            long long sc = improve(cur);\n            if (sc > best_score) {\n                best_score = sc;\n                best_parent = cur;\n            }\n        }\n\n        // random restarts until time limit\n        while (elapsed() < TL) {\n            vector<int> cur = make_initial(3);\n            long long sc = improve(cur);\n            if (sc > best_score) {\n                best_score = sc;\n                best_parent = cur;\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            if (v) cout << ' ';\n            cout << best_parent[v];\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ULL;\n    XorShift(uint64_t seed = 0) {\n        x ^= seed + 0x9e3779b97f4a7c15ULL;\n        next();\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) { // [l, r]\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic constexpr int INF = 1e9;\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    vector<pair<int,int>> oni, fuku;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') oni.push_back({i, j});\n            else if (C[i][j] == 'o') fuku.push_back({i, j});\n        }\n    }\n\n    const int P = (int)oni.size();      // should be 40\n    const int F = 4 * N;                // 80\n\n    vector<int> firstRowFuku(N, N), lastRowFuku(N, -1);\n    vector<int> firstColFuku(N, N), lastColFuku(N, -1);\n\n    for (auto [i, j] : fuku) {\n        firstRowFuku[i] = min(firstRowFuku[i], j);\n        lastRowFuku[i] = max(lastRowFuku[i], j);\n        firstColFuku[j] = min(firstColFuku[j], i);\n        lastColFuku[j] = max(lastColFuku[j], i);\n    }\n\n    auto idL = [&](int i) { return i; };\n    auto idR = [&](int i) { return N + i; };\n    auto idU = [&](int j) { return 2 * N + j; };\n    auto idD = [&](int j) { return 3 * N + j; };\n\n    vector<vector<int>> depth(P, vector<int>(F, INF));\n    vector<vector<int>> opts(P);\n    vector<vector<int>> candDepths(F);\n\n    for (int p = 0; p < P; p++) {\n        auto [i, j] = oni[p];\n\n        // Left\n        if (j < firstRowFuku[i]) {\n            int f = idL(i);\n            int d = j + 1;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Right\n        if (j > lastRowFuku[i]) {\n            int f = idR(i);\n            int d = N - j;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Up\n        if (i < firstColFuku[j]) {\n            int f = idU(j);\n            int d = i + 1;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Down\n        if (i > lastColFuku[j]) {\n            int f = idD(j);\n            int d = N - i;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n    }\n\n    for (int f = 0; f < F; f++) {\n        auto &v = candDepths[f];\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n    }\n\n    auto calcCost = [&](const vector<int>& assign) -> int {\n        vector<int> mx(F, 0);\n        for (int p = 0; p < P; p++) {\n            int f = assign[p];\n            mx[f] = max(mx[f], depth[p][f]);\n        }\n        int s = 0;\n        for (int f = 0; f < F; f++) s += mx[f];\n        return 2 * s;\n    };\n\n    auto hillClimb = [&](vector<int> assign) -> vector<int> {\n        int cur = calcCost(assign);\n        vector<int> mx(F);\n\n        while (true) {\n            int bestCost = cur;\n            int bestG = -1, bestM = -1;\n\n            for (int g = 0; g < F; g++) {\n                if (candDepths[g].empty()) continue;\n\n                for (int M : candDepths[g]) {\n                    fill(mx.begin(), mx.end(), 0);\n\n                    for (int p = 0; p < P; p++) {\n                        int nf = assign[p];\n                        if (depth[p][g] <= M) nf = g;\n                        mx[nf] = max(mx[nf], depth[p][nf]);\n                    }\n\n                    int s = 0;\n                    for (int f = 0; f < F; f++) s += mx[f];\n                    int nc = 2 * s;\n\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestG = g;\n                        bestM = M;\n                    }\n                }\n            }\n\n            if (bestG == -1) break;\n\n            for (int p = 0; p < P; p++) {\n                if (depth[p][bestG] <= bestM) assign[p] = bestG;\n            }\n            cur = bestCost;\n        }\n\n        return assign;\n    };\n\n    auto buildInitDet = [&]() -> vector<int> {\n        vector<int> order(P);\n        iota(order.begin(), order.end(), 0);\n\n        vector<int> minDepth(P, INF);\n        for (int p = 0; p < P; p++) {\n            for (int f : opts[p]) minDepth[p] = min(minDepth[p], depth[p][f]);\n        }\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if ((int)opts[a].size() != (int)opts[b].size())\n                return opts[a].size() < opts[b].size();\n            if (minDepth[a] != minDepth[b])\n                return minDepth[a] > minDepth[b];\n            return a < b;\n        });\n\n        vector<int> curMax(F, 0), assign(P, -1);\n\n        for (int p : order) {\n            int bestF = -1;\n            tuple<int,int,int,int> bestKey = {INF, INF, INF, INF};\n            for (int f : opts[p]) {\n                int d = depth[p][f];\n                int inc = max(0, d - curMax[f]);\n                auto key = make_tuple(inc, d, curMax[f], f);\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestF = f;\n                }\n            }\n            assign[p] = bestF;\n            curMax[bestF] = max(curMax[bestF], depth[p][bestF]);\n        }\n\n        return assign;\n    };\n\n    auto buildInitRandom = [&](XorShift& rng) -> vector<int> {\n        vector<int> order(P);\n        iota(order.begin(), order.end(), 0);\n        for (int i = P - 1; i >= 1; i--) {\n            int j = rng.next_int(0, i);\n            swap(order[i], order[j]);\n        }\n\n        vector<int> curMax(F, 0), assign(P, -1);\n\n        for (int p : order) {\n            vector<tuple<int,int,int>> cand; // (inc, depth, facility)\n            for (int f : opts[p]) {\n                int d = depth[p][f];\n                int inc = max(0, d - curMax[f]);\n                cand.emplace_back(inc, d, f);\n            }\n            sort(cand.begin(), cand.end());\n\n            int chooseF;\n            if ((int)cand.size() == 1) {\n                chooseF = get<2>(cand[0]);\n            } else {\n                int k = min<int>(3, cand.size());\n                if (rng.next_int(0, 99) < 85) {\n                    // weighted among top k: k, k-1, ...\n                    int total = k * (k + 1) / 2;\n                    int x = rng.next_int(1, total);\n                    int acc = 0, pick = 0;\n                    for (int t = 0; t < k; t++) {\n                        acc += (k - t);\n                        if (x <= acc) {\n                            pick = t;\n                            break;\n                        }\n                    }\n                    chooseF = get<2>(cand[pick]);\n                } else {\n                    chooseF = get<2>(cand[rng.next_int(0, (int)cand.size() - 1)]);\n                }\n            }\n\n            assign[p] = chooseF;\n            curMax[chooseF] = max(curMax[chooseF], depth[p][chooseF]);\n        }\n\n        return assign;\n    };\n\n    auto perturb = [&](const vector<int>& base, XorShift& rng) -> vector<int> {\n        vector<int> a = base;\n        int changes = rng.next_int(1, 6);\n        for (int t = 0; t < changes; t++) {\n            int p = rng.next_int(0, P - 1);\n            int idx = rng.next_int(0, (int)opts[p].size() - 1);\n            a[p] = opts[p][idx];\n        }\n        return a;\n    };\n\n    uint64_t seed = 0;\n    for (auto &row : C) {\n        for (char ch : row) seed = seed * 131 + ch;\n    }\n    XorShift rng(seed ^ 0x123456789abcdefULL);\n\n    auto start = chrono::steady_clock::now();\n    auto deadline = start + chrono::milliseconds(1850);\n\n    vector<int> bestAssign = hillClimb(buildInitDet());\n    int bestCost = calcCost(bestAssign);\n\n    int iter = 0;\n    while (chrono::steady_clock::now() < deadline) {\n        vector<int> init;\n        if (iter < 20) {\n            init = buildInitRandom(rng);\n        } else if (iter % 3 == 0) {\n            init = perturb(bestAssign, rng);\n        } else {\n            init = buildInitRandom(rng);\n        }\n\n        auto sol = hillClimb(init);\n        int cost = calcCost(sol);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestAssign = std::move(sol);\n        }\n        iter++;\n    }\n\n    vector<int> maxDepth(F, 0);\n    for (int p = 0; p < P; p++) {\n        int f = bestAssign[p];\n        maxDepth[f] = max(maxDepth[f], depth[p][f]);\n    }\n\n    vector<pair<char,int>> ans;\n    ans.reserve(bestCost);\n\n    for (int f = 0; f < F; f++) {\n        int k = maxDepth[f];\n        if (k == 0) continue;\n\n        if (f < N) {\n            int i = f;\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n        } else if (f < 2 * N) {\n            int i = f - N;\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n        } else if (f < 3 * N) {\n            int j = f - 2 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n        } else {\n            int j = f - 3 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n        }\n    }\n\n    // Safety fallback (should not be needed).\n    if ((int)ans.size() > 4 * N * N) {\n        ans.clear();\n        for (int p = 0; p < P; p++) {\n            auto [i, j] = oni[p];\n            int bestF = -1, bestD = INF;\n            for (int f : opts[p]) {\n                if (depth[p][f] < bestD) {\n                    bestD = depth[p][f];\n                    bestF = f;\n                }\n            }\n            int k = bestD;\n            if (bestF < N) {\n                for (int t = 0; t < k; t++) ans.push_back({'L', i});\n                for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            } else if (bestF < 2 * N) {\n                for (int t = 0; t < k; t++) ans.push_back({'R', i});\n                for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            } else if (bestF < 3 * N) {\n                int col = j;\n                for (int t = 0; t < k; t++) ans.push_back({'U', col});\n                for (int t = 0; t < k; t++) ans.push_back({'D', col});\n            } else {\n                int col = j;\n                for (int t = 0; t < k; t++) ans.push_back({'D', col});\n                for (int t = 0; t < k; t++) ans.push_back({'U', col});\n            }\n        }\n    }\n\n    for (auto [c, p] : ans) {\n        cout << c << ' ' << p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\n#include <atcoder/scc>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic inline long long llabs2(long long x) { return x >= 0 ? x : -x; }\n\nstruct State {\n    vector<int> a, b;\n    vector<int> cnt;\n    long long err = (1LL << 60);\n};\n\nstruct Solver {\n    int N, L;\n    vector<int> T;\n    mt19937_64 rng;\n\n    chrono::steady_clock::time_point st;\n\n    Solver(int N_, int L_, vector<int> T_)\n        : N(N_), L(L_), T(std::move(T_)),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    State simulate(const vector<int>& a, const vector<int>& b) {\n        State res;\n        res.a = a;\n        res.b = b;\n        res.cnt.assign(N, 0);\n\n        int x = 0;\n        res.cnt[0] = 1;\n        for (int step = 1; step < L; step++) {\n            x = (res.cnt[x] & 1) ? a[x] : b[x];\n            res.cnt[x]++;\n        }\n\n        long long err = 0;\n        for (int i = 0; i < N; i++) err += llabs2((long long)res.cnt[i] - T[i]);\n        res.err = err;\n        return res;\n    }\n\n    vector<vector<int>> get_sccs(const vector<int>& a, const vector<int>& b) {\n        scc_graph g(N);\n        for (int i = 0; i < N; i++) {\n            g.add_edge(i, a[i]);\n            g.add_edge(i, b[i]);\n        }\n        return g.scc();\n    }\n\n    void repair_components(vector<int>& a, vector<int>& b, vector<long long>& R) {\n        // Try a few times. Usually one pass is enough.\n        for (int iter = 0; iter < 4; iter++) {\n            auto comps = get_sccs(a, b);\n            if ((int)comps.size() <= 1) return;\n\n            vector<int> comp_id(N, -1);\n            for (int i = 0; i < (int)comps.size(); i++) {\n                for (int v : comps[i]) comp_id[v] = i;\n            }\n\n            int K = (int)comps.size();\n            vector<int> rep(K, -1);\n            for (int i = 0; i < K; i++) {\n                int best = comps[i][0];\n                for (int v : comps[i]) {\n                    if (T[v] < T[best]) best = v;\n                }\n                rep[i] = best;\n            }\n\n            // Connect components in a cycle with minimum-damage rewiring.\n            for (int i = 0; i < K; i++) {\n                int target = rep[(i + 1) % K];\n\n                long long bestKey = (1LL << 62);\n                int bestu = -1, bestslot = -1, bestold = -1;\n\n                for (int u : comps[i]) {\n                    long long w = T[u];\n                    for (int slot = 0; slot < 2; slot++) {\n                        int old = (slot == 0 ? a[u] : b[u]);\n                        if (old == target) {\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestKey = LLONG_MIN;\n                            break;\n                        }\n\n                        long long delta =\n                            llabs2(R[old] + w) + llabs2(R[target] - w)\n                            - llabs2(R[old]) - llabs2(R[target]);\n\n                        int other = (slot == 0 ? b[u] : a[u]);\n                        long long key = delta * 1000000LL + T[u];\n                        if (comp_id[other] == i) key -= 1; // slight preference\n\n                        if (key < bestKey) {\n                            bestKey = key;\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                        }\n                    }\n                    if (bestKey == LLONG_MIN) break;\n                }\n\n                if (bestu != -1 && bestold != target) {\n                    long long w = T[bestu];\n                    R[bestold] += w;\n                    R[target] -= w;\n                    if (bestslot == 0) a[bestu] = target;\n                    else b[bestu] = target;\n                }\n            }\n        }\n    }\n\n    State build_candidate(int mode) {\n        vector<long long> R(N);\n        for (int i = 0; i < N; i++) R[i] = 2LL * T[i];\n\n        vector<int> dest(2 * N, -1);\n        vector<int> first_dest(N, -1);\n\n        vector<int> ids(2 * N);\n        iota(ids.begin(), ids.end(), 0);\n\n        // Different modes for diversification.\n        long long same_pen = (mode % 4 == 0 ? 0 : mode % 4 == 1 ? 50 : mode % 4 == 2 ? 200 : 800);\n        long long self_pen = (mode % 5 == 0 ? 0 : mode % 5 == 1 ? 50 : mode % 5 == 2 ? 200 : mode % 5 == 3 ? 800 : 2000);\n\n        shuffle(ids.begin(), ids.end(), rng);\n        stable_sort(ids.begin(), ids.end(), [&](int p, int q) {\n            int wp = T[p / 2], wq = T[q / 2];\n            if (wp != wq) return wp > wq;\n            return p < q;\n        });\n\n        for (int pid : ids) {\n            int owner = pid / 2;\n            long long w = T[owner];\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(N);\n\n            for (int j = 0; j < N; j++) {\n                long long after = R[j] - w;\n                long long sc = llabs2(after) * 10;\n                if (after < 0) sc += (-after);          // slight overshoot penalty\n                if (first_dest[owner] == j) sc += same_pen;\n                if (j == owner) sc += self_pen;\n                sc += (long long)(rng() % 17);\n                cand.push_back({sc, j});\n            }\n\n            nth_element(cand.begin(), cand.begin() + min(4, N - 1), cand.end());\n            sort(cand.begin(), cand.begin() + min(5, N));\n\n            int pick_lim = min(5, N);\n            int choose = (int)(rng() % pick_lim);\n            int j = cand[choose].second;\n\n            dest[pid] = j;\n            if (first_dest[owner] == -1) first_dest[owner] = j;\n            R[j] -= w;\n        }\n\n        // Local improvement: single moves.\n        for (int pass = 0; pass < 5; pass++) {\n            bool changed = false;\n            shuffle(ids.begin(), ids.end(), rng);\n            for (int pid : ids) {\n                int owner = pid / 2;\n                long long w = T[owner];\n                int u = dest[pid];\n\n                long long bestDelta = 0;\n                int bestV = u;\n                for (int v = 0; v < N; v++) if (v != u) {\n                    long long delta =\n                        llabs2(R[u] + w) + llabs2(R[v] - w)\n                        - llabs2(R[u]) - llabs2(R[v]);\n\n                    if (delta < bestDelta || (delta == bestDelta && (rng() & 1))) {\n                        bestDelta = delta;\n                        bestV = v;\n                    }\n                }\n\n                if (bestV != u && bestDelta < 0) {\n                    R[u] += w;\n                    R[bestV] -= w;\n                    dest[pid] = bestV;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n\n        // Local improvement: random swaps.\n        for (int it = 0; it < 400; it++) {\n            int p = rng() % (2 * N);\n            int q = rng() % (2 * N);\n            if (p == q) continue;\n            int u = dest[p], v = dest[q];\n            if (u == v) continue;\n            long long w1 = T[p / 2], w2 = T[q / 2];\n\n            long long delta =\n                llabs2(R[u] + w1 - w2) + llabs2(R[v] + w2 - w1)\n                - llabs2(R[u]) - llabs2(R[v]);\n\n            if (delta < 0) {\n                R[u] += w1 - w2;\n                R[v] += w2 - w1;\n                swap(dest[p], dest[q]);\n            }\n        }\n\n        vector<int> a(N), b(N);\n        for (int i = 0; i < N; i++) {\n            a[i] = dest[2 * i];\n            b[i] = dest[2 * i + 1];\n            if (rng() & 1) swap(a[i], b[i]);\n        }\n\n        repair_components(a, b, R);\n\n        return simulate(a, b);\n    }\n\n    State hill_climb(State cur) {\n        while (elapsed() < 1.95) {\n            vector<int> over, under;\n            for (int i = 0; i < N; i++) {\n                long long d = (long long)cur.cnt[i] - T[i];\n                if (d > 0) over.push_back(i);\n                if (d < 0) under.push_back(i);\n            }\n\n            sort(over.begin(), over.end(), [&](int x, int y) {\n                return (cur.cnt[x] - T[x]) > (cur.cnt[y] - T[y]);\n            });\n            sort(under.begin(), under.end(), [&](int x, int y) {\n                return (T[x] - cur.cnt[x]) > (T[y] - cur.cnt[y]);\n            });\n\n            bool improved = false;\n            int tries = 0;\n            while (tries < 20 && elapsed() < 1.95) {\n                tries++;\n\n                State nxt = cur;\n                int typ = rng() % 3;\n\n                if (typ == 2) {\n                    // swap a/b on one node\n                    int i;\n                    if (!over.empty() && (rng() & 1)) i = over[rng() % min<int>(10, over.size())];\n                    else i = rng() % N;\n                    if (nxt.a[i] == nxt.b[i]) continue;\n                    swap(nxt.a[i], nxt.b[i]);\n                } else {\n                    int i;\n                    if (!over.empty()) i = over[rng() % min<int>(10, over.size())];\n                    else i = rng() % N;\n\n                    int j;\n                    if (!under.empty()) j = under[rng() % min<int>(10, under.size())];\n                    else j = rng() % N;\n\n                    if (typ == 0) {\n                        if (nxt.a[i] == j) continue;\n                        nxt.a[i] = j;\n                    } else {\n                        if (nxt.b[i] == j) continue;\n                        nxt.b[i] = j;\n                    }\n                }\n\n                nxt = simulate(nxt.a, nxt.b);\n                if (nxt.err < cur.err) {\n                    cur = std::move(nxt);\n                    improved = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    State solve() {\n        State best;\n\n        int mode = 0;\n        while (elapsed() < 1.15) {\n            State cand = build_candidate(mode++);\n            if (cand.err < best.err) best = std::move(cand);\n        }\n\n        best = hill_climb(best);\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    vector<int> T(N);\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    Solver solver(N, L, T);\n    State ans = solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << ans.a[i] << ' ' << ans.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<double> cx, cy;\n    vector<vector<double>> distm;\n    vector<uint32_t> morton_code;\n    int used_queries = 0;\n\n    static constexpr double INF = 1e100;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffff;\n        x = (x ^ (x << 8)) & 0x00FF00FF;\n        x = (x ^ (x << 4)) & 0x0F0F0F0F;\n        x = (x ^ (x << 2)) & 0x33333333;\n        x = (x ^ (x << 1)) & 0x55555555;\n        return x;\n    }\n\n    static pair<int,int> norm_edge(int a, int b) {\n        if (a > b) swap(a, b);\n        return {a, b};\n    }\n\n    void input() {\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        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx.resize(N); cy.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n        }\n\n        distm.assign(N, vector<double>(N, 0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                double dx = cx[i] - cx[j];\n                double dy = cy[i] - cy[j];\n                double d = sqrt(dx * dx + dy * dy);\n                distm[i][j] = distm[j][i] = d;\n            }\n        }\n\n        morton_code.resize(N);\n        for (int i = 0; i < N; i++) {\n            int xi = int(round(cx[i]));\n            int yi = int(round(cy[i]));\n            xi = max(0, min(16383, xi));\n            yi = max(0, min(16383, yi));\n            morton_code[i] = part1by1((uint32_t)xi) | (part1by1((uint32_t)yi) << 1);\n        }\n    }\n\n    vector<int> make_morton_order() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_projection_order(double theta) {\n        double ct = cos(theta), st = sin(theta);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double ka = cx[a] * ct + cy[a] * st;\n            double kb = cx[b] * ct + cy[b] * st;\n            if (fabs(ka - kb) > 1e-9) return ka < kb;\n            double ta = -cx[a] * st + cy[a] * ct;\n            double tb = -cx[b] * st + cy[b] * ct;\n            if (fabs(ta - tb) > 1e-9) return ta < tb;\n            return a < b;\n        });\n        return ord;\n    }\n\n    double mst_cost_of_list(const vector<int>& cities) {\n        int n = (int)cities.size();\n        if (n <= 1) return 0.0;\n        vector<double> md(n, INF);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n        double ret = 0.0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            ret += md[v];\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) {\n                if (!used[i]) {\n                    double d = distm[cv][cities[i]];\n                    if (d < md[i]) md[i] = d;\n                }\n            }\n        }\n        return ret;\n    }\n\n    struct OrderEvaluator {\n        const vector<int>& ord;\n        const vector<vector<double>>& distm;\n        int N;\n        vector<vector<double>> cache; // cache[l][len]\n\n        OrderEvaluator(const vector<int>& ord_, const vector<vector<double>>& distm_)\n            : ord(ord_), distm(distm_), N((int)ord_.size()),\n              cache(N + 1, vector<double>(N + 1, -1.0)) {}\n\n        double seg_cost(int l, int len) {\n            if (len <= 1) return 0.0;\n            double &res = cache[l][len];\n            if (res >= -0.5) return res;\n\n            vector<double> md(len, 1e100);\n            vector<char> used(len, 0);\n            md[0] = 0.0;\n            double ret = 0.0;\n            for (int it = 0; it < len; it++) {\n                int v = -1;\n                for (int i = 0; i < len; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                ret += md[v];\n                int cv = ord[l + v];\n                for (int i = 0; i < len; i++) {\n                    if (!used[i]) {\n                        double d = distm[cv][ord[l + i]];\n                        if (d < md[i]) md[i] = d;\n                    }\n                }\n            }\n            res = ret;\n            return res;\n        }\n\n        double total_cost(const vector<int>& sizes) {\n            int pos = 0;\n            double ret = 0.0;\n            for (int s : sizes) {\n                ret += seg_cost(pos, s);\n                pos += s;\n            }\n            return ret;\n        }\n\n        vector<int> improve(vector<int> sizes, int passes = 4) {\n            int M = (int)sizes.size();\n            for (int pass = 0; pass < passes; pass++) {\n                bool any = false;\n                // forward\n                int pos = 0;\n                for (int k = 0; k + 1 < M; k++) {\n                    int a = sizes[k], b = sizes[k + 1];\n                    double oldc = seg_cost(pos, a) + seg_cost(pos + a, b);\n                    double newc = seg_cost(pos, b) + seg_cost(pos + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[k], sizes[k + 1]);\n                        any = true;\n                    }\n                    pos += sizes[k];\n                }\n                // backward\n                vector<int> pref(M + 1, 0);\n                for (int i = 0; i < M; i++) pref[i + 1] = pref[i] + sizes[i];\n                for (int k = M - 2; k >= 0; k--) {\n                    int pos2 = pref[k];\n                    int a = sizes[k], b = sizes[k + 1];\n                    double oldc = seg_cost(pos2, a) + seg_cost(pos2 + a, b);\n                    double newc = seg_cost(pos2, b) + seg_cost(pos2 + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[k], sizes[k + 1]);\n                        any = true;\n                    }\n                }\n                if (!any) break;\n            }\n            return sizes;\n        }\n    };\n\n    struct GroupingResult {\n        vector<vector<int>> groups_by_original_idx;\n        vector<vector<int>> segment_order_groups; // same cities, but in chosen segment order, indexed by original idx\n        double score = INF;\n    };\n\n    GroupingResult build_groups() {\n        vector<vector<int>> order_candidates;\n        order_candidates.push_back(make_morton_order());\n        for (int t = 0; t < 8; t++) {\n            double theta = M_PI * t / 8.0;\n            order_candidates.push_back(make_projection_order(theta));\n        }\n\n        vector<int> ascG = G;\n        sort(ascG.begin(), ascG.end());\n        vector<int> descG = G;\n        sort(descG.rbegin(), descG.rend());\n        vector<vector<int>> init_size_sequences = {ascG, descG, G};\n\n        double best_score = INF;\n        vector<int> best_ord;\n        vector<int> best_sizes;\n\n        for (const auto& ord : order_candidates) {\n            OrderEvaluator eval(ord, distm);\n            for (auto init_sizes : init_size_sequences) {\n                auto sizes = eval.improve(init_sizes);\n                double sc = eval.total_cost(sizes);\n                if (sc < best_score) {\n                    best_score = sc;\n                    best_ord = ord;\n                    best_sizes = sizes;\n                }\n            }\n        }\n\n        vector<vector<int>> groups(M);\n        vector<vector<int>> seg_groups;\n\n        int pos = 0;\n        for (int s : best_sizes) {\n            vector<int> grp;\n            grp.reserve(s);\n            for (int i = 0; i < s; i++) grp.push_back(best_ord[pos + i]);\n            pos += s;\n            seg_groups.push_back(grp);\n        }\n\n        unordered_map<int, vector<int>> idx_of_size;\n        idx_of_size.reserve(M * 2);\n        for (int i = 0; i < M; i++) idx_of_size[G[i]].push_back(i);\n        for (auto& [k, v] : idx_of_size) reverse(v.begin(), v.end());\n\n        vector<vector<int>> groups_by_original_idx(M), segment_order_groups(M);\n        for (auto& grp : seg_groups) {\n            int s = (int)grp.size();\n            int idx = idx_of_size[s].back();\n            idx_of_size[s].pop_back();\n            groups_by_original_idx[idx] = grp;\n            segment_order_groups[idx] = grp;\n        }\n\n        return {groups_by_original_idx, segment_order_groups, best_score};\n    }\n\n    vector<int> block_sizes_balanced(int g) {\n        if (g <= 1) return {};\n        int b = (g + L - 1) / L;\n        int base = g / b;\n        int rem = g % b;\n        vector<int> res(b, base);\n        for (int i = 0; i < rem; i++) res[i]++;\n        return res;\n    }\n\n    double best_pair_distance_between_blocks(const vector<int>& A, const vector<int>& B, pair<int,int>* best_edge = nullptr) {\n        double best = INF;\n        pair<int,int> e = {-1, -1};\n        for (int u : A) {\n            for (int v : B) {\n                double d = distm[u][v];\n                if (d < best) {\n                    best = d;\n                    e = norm_edge(u, v);\n                }\n            }\n        }\n        if (best_edge) *best_edge = e;\n        return best;\n    }\n\n    double approx_group_plan_cost(const vector<int>& ordered_group) {\n        int g = (int)ordered_group.size();\n        if (g <= 1) return 0.0;\n        if (g <= L) return mst_cost_of_list(ordered_group);\n\n        auto bs = block_sizes_balanced(g);\n        vector<vector<int>> blocks;\n        blocks.reserve(bs.size());\n\n        int pos = 0;\n        double cost = 0.0;\n        for (int s : bs) {\n            vector<int> blk;\n            blk.reserve(s);\n            for (int i = 0; i < s; i++) blk.push_back(ordered_group[pos + i]);\n            pos += s;\n            cost += mst_cost_of_list(blk);\n            blocks.push_back(move(blk));\n        }\n\n        int B = (int)blocks.size();\n        vector<double> md(B, INF);\n        vector<char> used(B, 0);\n        md[0] = 0.0;\n        for (int it = 0; it < B; it++) {\n            int v = -1;\n            for (int i = 0; i < B; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            cost += md[v];\n            for (int i = 0; i < B; i++) {\n                if (!used[i]) {\n                    double w = best_pair_distance_between_blocks(blocks[v], blocks[i], nullptr);\n                    if (w < md[i]) md[i] = w;\n                }\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> query(const vector<int>& cities) {\n        cout << \"? \" << cities.size();\n        for (int x : cities) cout << \" \" << x;\n        cout << endl;\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)cities.size() - 1);\n        for (int i = 0; i < (int)cities.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            ret.push_back(norm_edge(a, b));\n        }\n        used_queries++;\n        return ret;\n    }\n\n    struct GroupAnswer {\n        vector<int> cities;\n        vector<pair<int,int>> edges;\n    };\n\n    GroupAnswer solve_one_group(vector<int> group_cities) {\n        int g = (int)group_cities.size();\n        GroupAnswer ans;\n        ans.cities = group_cities;\n\n        if (g <= 1) return ans;\n\n        if (g <= L) {\n            ans.edges = query(group_cities);\n            return ans;\n        }\n\n        vector<int> morton_sorted = group_cities;\n        sort(morton_sorted.begin(), morton_sorted.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n\n        // choose better local order\n        double cost1 = approx_group_plan_cost(group_cities);\n        double cost2 = approx_group_plan_cost(morton_sorted);\n        if (cost2 < cost1) group_cities = morton_sorted;\n\n        ans.cities = group_cities;\n\n        auto bs = block_sizes_balanced(g);\n        vector<vector<int>> blocks;\n        blocks.reserve(bs.size());\n\n        int pos = 0;\n        for (int s : bs) {\n            vector<int> blk;\n            blk.reserve(s);\n            for (int i = 0; i < s; i++) blk.push_back(group_cities[pos + i]);\n            pos += s;\n            blocks.push_back(move(blk));\n        }\n\n        // exact MST inside each block\n        for (auto& blk : blocks) {\n            auto e = query(blk);\n            ans.edges.insert(ans.edges.end(), e.begin(), e.end());\n        }\n\n        // connect blocks by estimated MST over block graph\n        int B = (int)blocks.size();\n        if (B >= 2) {\n            vector<vector<double>> bw(B, vector<double>(B, INF));\n            vector<vector<pair<int,int>>> bedge(B, vector<pair<int,int>>(B, {-1, -1}));\n\n            for (int i = 0; i < B; i++) {\n                for (int j = i + 1; j < B; j++) {\n                    pair<int,int> e;\n                    double w = best_pair_distance_between_blocks(blocks[i], blocks[j], &e);\n                    bw[i][j] = bw[j][i] = w;\n                    bedge[i][j] = bedge[j][i] = e;\n                }\n            }\n\n            vector<double> md(B, INF);\n            vector<int> par(B, -1);\n            vector<char> used(B, 0);\n            md[0] = 0.0;\n            for (int it = 0; it < B; it++) {\n                int v = -1;\n                for (int i = 0; i < B; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                if (par[v] != -1) {\n                    ans.edges.push_back(bedge[v][par[v]]);\n                }\n                for (int i = 0; i < B; i++) {\n                    if (!used[i] && bw[v][i] < md[i]) {\n                        md[i] = bw[v][i];\n                        par[i] = v;\n                    }\n                }\n            }\n        }\n\n        return ans;\n    }\n\n    void solve() {\n        input();\n\n        auto grouping = build_groups();\n\n        long long planned_queries = 0;\n        for (int i = 0; i < M; i++) {\n            int g = G[i];\n            if (g >= 2) planned_queries += (g + L - 1) / L;\n        }\n        // safety: should always fit\n        if (planned_queries > Q) {\n            // extremely defensive fallback, though this should not happen\n            // with this construction under given constraints.\n        }\n\n        vector<GroupAnswer> answers(M);\n        for (int i = 0; i < M; i++) {\n            answers[i] = solve_one_group(grouping.segment_order_groups[i]);\n        }\n\n        cout << \"!\" << endl;\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < (int)answers[i].cities.size(); j++) {\n                if (j) cout << ' ';\n                cout << answers[i].cities[j];\n            }\n            cout << '\\n';\n            for (auto [a, b] : answers[i].edges) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int POS = N * N;          // 400\nstatic constexpr int NONE = POS;           // 400 means no internal block\nstatic constexpr int BNUM = POS + 1;       // 401\nstatic constexpr int STATES = POS * BNUM;  // 160400\nstatic constexpr int INF = 1e9;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar dch[4] = {'U', 'D', 'L', 'R'};\n\ninline int sid(int pos, int b) { return pos * BNUM + b; }\ninline int pos_of(int s) { return s / BNUM; }\ninline int block_of(int s) { return s % BNUM; }\n\nint neigh[POS][4];                 // adjacent cell for each direction, -1 if outside\nunsigned short slide_to[BNUM][POS][4]; // stop position when sliding with fixed block b\n\n// For main BFS\nint dist_state[STATES];\nint parent_state[STATES];\nunsigned char parent_op[STATES];   // 0..11 : action*4 + dir\n\n// Encode: 0..3 Move, 4..7 Slide, 8..11 Alter\ninline char act_char(int code) {\n    if (code < 4) return 'M';\n    if (code < 8) return 'S';\n    return 'A';\n}\ninline char dir_char(int code) {\n    return dch[code & 3];\n}\n\nvoid precompute() {\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int p = r * N + c;\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                    neigh[p][d] = nr * N + nc;\n                } else {\n                    neigh[p][d] = -1;\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int p = 0; p < POS; p++) {\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; d++) {\n                int cr = r, cc = c;\n                while (true) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) break;\n                    int np = nr * N + nc;\n                    if (b != NONE && np == b) break;\n                    cr = nr;\n                    cc = nc;\n                }\n                slide_to[b][p][d] = (unsigned short)(cr * N + cc);\n            }\n        }\n    }\n}\n\n// Heuristic:\n// from (startPos, block b or none), estimate cost to targetPos in a reduced model:\n// - Move / Slide are allowed\n// - Existing block may be removed by Alter if adjacent\n// - No new blocks may be placed\nint estimate_remove_only(int startPos, int targetPos, int b) {\n    if (startPos == targetPos) return 0;\n\n    static int dist[POS * 2];\n    fill(dist, dist + POS * 2, -1);\n\n    auto id2 = [](int pos, int alive) { return pos * 2 + alive; };\n    deque<int> q;\n\n    int alive0 = (b == NONE ? 0 : 1);\n    int s0 = id2(startPos, alive0);\n    dist[s0] = 0;\n    q.push_back(s0);\n\n    while (!q.empty()) {\n        int s = q.front(); q.pop_front();\n        int p = s / 2;\n        int alive = s & 1;\n        int curd = dist[s];\n        int curBlock = alive ? b : NONE;\n\n        if (p == targetPos) return curd;\n\n        // Move / Slide\n        for (int d = 0; d < 4; d++) {\n            int np = neigh[p][d];\n            if (np != -1 && np != curBlock) {\n                int ns = id2(np, alive);\n                if (dist[ns] == -1) {\n                    dist[ns] = curd + 1;\n                    q.push_back(ns);\n                }\n            }\n            int sp = slide_to[curBlock][p][d];\n            if (sp != p) {\n                int ns = id2(sp, alive);\n                if (dist[ns] == -1) {\n                    dist[ns] = curd + 1;\n                    q.push_back(ns);\n                }\n            }\n        }\n\n        // Remove existing block if adjacent\n        if (alive) {\n            for (int d = 0; d < 4; d++) {\n                int ap = neigh[p][d];\n                if (ap == b) {\n                    int ns = id2(p, 0);\n                    if (dist[ns] == -1) {\n                        dist[ns] = curd + 1;\n                        q.push_back(ns);\n                    }\n                }\n            }\n        }\n    }\n    return INF / 4;\n}\n\n// BFS in the restricted full model (at most one internal block).\n// Returns chosen goal state, and reconstructable parents are stored globally.\nint bfs_to_target_choose_state(int startState, int targetPos, int nextTargetPos, bool hasNext) {\n    fill(dist_state, dist_state + STATES, -1);\n\n    deque<int> q;\n    dist_state[startState] = 0;\n    parent_state[startState] = -1;\n    parent_op[startState] = 255;\n    q.push_back(startState);\n\n    int bestDist = INF;\n    vector<int> goals;\n    goals.reserve(64);\n\n    while (!q.empty()) {\n        int s = q.front(); q.pop_front();\n        int dcur = dist_state[s];\n        if (dcur > bestDist) break;\n\n        int p = pos_of(s);\n        int b = block_of(s);\n\n        // Move\n        for (int dir = 0; dir < 4; dir++) {\n            int np = neigh[p][dir];\n            if (np != -1 && np != b) {\n                int ns = sid(np, b);\n                if (dist_state[ns] == -1) {\n                    dist_state[ns] = dcur + 1;\n                    parent_state[ns] = s;\n                    parent_op[ns] = (unsigned char)(0 + dir);\n                    if (np == targetPos) {\n                        if (bestDist == INF) bestDist = dcur + 1;\n                        if (dcur + 1 == bestDist) goals.push_back(ns);\n                    }\n                    q.push_back(ns);\n                }\n            }\n        }\n\n        // Slide\n        for (int dir = 0; dir < 4; dir++) {\n            int sp = slide_to[b][p][dir];\n            if (sp != p) {\n                int ns = sid(sp, b);\n                if (dist_state[ns] == -1) {\n                    dist_state[ns] = dcur + 1;\n                    parent_state[ns] = s;\n                    parent_op[ns] = (unsigned char)(4 + dir);\n                    if (sp == targetPos) {\n                        if (bestDist == INF) bestDist = dcur + 1;\n                        if (dcur + 1 == bestDist) goals.push_back(ns);\n                    }\n                    q.push_back(ns);\n                }\n            }\n        }\n\n        // Alter\n        for (int dir = 0; dir < 4; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n\n            int nb = -1;\n            if (b == NONE) {\n                nb = ap;          // place one block\n            } else if (b == ap) {\n                nb = NONE;        // remove the only block\n            } else {\n                continue;         // do not create 2nd block in this model\n            }\n\n            int ns = sid(p, nb);\n            if (dist_state[ns] == -1) {\n                dist_state[ns] = dcur + 1;\n                parent_state[ns] = s;\n                parent_op[ns] = (unsigned char)(8 + dir);\n                // position unchanged, so no need to check goal unless start was already target (it is not)\n                q.push_back(ns);\n            }\n        }\n    }\n\n    // Safety fallback (should never happen)\n    if (goals.empty()) {\n        return -1;\n    }\n\n    if (!hasNext) {\n        // Final target: prefer no block, otherwise any\n        int best = goals[0];\n        int bestBlock = block_of(best);\n        for (int g : goals) {\n            int bg = block_of(g);\n            if (bestBlock != NONE && bg == NONE) {\n                best = g;\n                bestBlock = bg;\n            }\n        }\n        return best;\n    }\n\n    // One-step lookahead by reduced-model BFS\n    int bestGoal = goals[0];\n    int bestEval = INF;\n    int bestKeep = 1; // prefer no block on tie\n\n    for (int g : goals) {\n        int b = block_of(g);\n        int eval = estimate_remove_only(targetPos, nextTargetPos, b);\n        int keep = (b == NONE ? 0 : 1);\n        if (eval < bestEval || (eval == bestEval && keep < bestKeep)) {\n            bestEval = eval;\n            bestKeep = keep;\n            bestGoal = g;\n        }\n    }\n    return bestGoal;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    int M;\n    cin >> ws;\n    int Nin;\n    cin >> Nin >> M;\n    vector<int> pts(M);\n    for (int k = 0; k < M; k++) {\n        int i, j;\n        cin >> i >> j;\n        pts[k] = i * N + j;\n    }\n\n    vector<pair<char, char>> answer;\n    answer.reserve(1600);\n\n    int curPos = pts[0];  // initial position\n    int curBlock = NONE;  // start with no internal block\n\n    for (int k = 1; k < M; k++) {\n        int target = pts[k];\n        bool hasNext = (k + 1 < M);\n        int nextTarget = hasNext ? pts[k + 1] : -1;\n\n        int startState = sid(curPos, curBlock);\n        int goalState = bfs_to_target_choose_state(startState, target, nextTarget, hasNext);\n\n        if (goalState == -1) {\n            // Extremely unlikely fallback: pure moves while removing block if necessary.\n            int p = curPos;\n            int b = curBlock;\n\n            auto apply_move = [&](int dir) {\n                answer.push_back({'M', dch[dir]});\n                p = neigh[p][dir];\n            };\n            auto apply_remove_if_needed = [&](int cell) {\n                if (b == cell) {\n                    // must be adjacent to remove\n                    int pr = p / N, pc = p % N;\n                    int tr = cell / N, tc = cell % N;\n                    for (int d = 0; d < 4; d++) {\n                        if (pr + dr[d] == tr && pc + dc[d] == tc) {\n                            answer.push_back({'A', dch[d]});\n                            b = NONE;\n                            return;\n                        }\n                    }\n                }\n            };\n\n            while (p != target) {\n                int pr = p / N, pc = p % N;\n                int tr = target / N, tc = target % N;\n                if (pr < tr) {\n                    int np = neigh[p][1];\n                    apply_remove_if_needed(np);\n                    apply_move(1);\n                } else if (pr > tr) {\n                    int np = neigh[p][0];\n                    apply_remove_if_needed(np);\n                    apply_move(0);\n                } else if (pc < tc) {\n                    int np = neigh[p][3];\n                    apply_remove_if_needed(np);\n                    apply_move(3);\n                } else {\n                    int np = neigh[p][2];\n                    apply_remove_if_needed(np);\n                    apply_move(2);\n                }\n            }\n            curPos = p;\n            curBlock = b;\n            continue;\n        }\n\n        // Reconstruct path\n        vector<unsigned char> ops;\n        int s = goalState;\n        while (s != startState) {\n            ops.push_back(parent_op[s]);\n            s = parent_state[s];\n        }\n        reverse(ops.begin(), ops.end());\n\n        for (unsigned char code : ops) {\n            answer.push_back({act_char(code), dir_char(code)});\n        }\n\n        curPos = pos_of(goalState);\n        curBlock = block_of(goalState);\n    }\n\n    // Safety: action limit is 2*N*M = 1600\n    if ((int)answer.size() > 2 * N * M) {\n        // If somehow exceeded, output only prefix to stay legal.\n        // (Practically this solver should stay well below.)\n        answer.resize(2 * N * M);\n    }\n\n    for (auto [a, d] : answer) {\n        cout << a << ' ' << d << '\\n';\n    }\n    return 0;\n}"},"2":{"ahc001":"#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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct State {\n    double score;\n    vector<Rect> rects;\n};\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr double TL = 4.95;\n\nint n;\nvector<int> X, Y;\nvector<long long> Rr;\n\nTimer timer;\nmt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline long long area(const Rect& r) {\n    return 1LL * (r.c - r.a) * (r.d - r.b);\n}\n\ninline double sat(long long s, long long r) {\n    double q = (double)min(s, r) / (double)max(s, r);\n    double t = 1.0 - q;\n    return 1.0 - t * t;\n}\n\ninline double local_score(const Rect& r, int i) {\n    return sat(area(r), Rr[i]);\n}\n\ndouble total_score(const vector<Rect>& rects) {\n    double res = 0.0;\n    for (int i = 0; i < n; ++i) res += local_score(rects[i], i);\n    return res;\n}\n\ninline bool hoverlap(const Rect& x, const Rect& y) {\n    return max(x.a, y.a) < min(x.c, y.c);\n}\n\ninline bool voverlap(const Rect& x, const Rect& y) {\n    return max(x.b, y.b) < min(x.d, y.d);\n}\n\n// ============================================================\n// Initial construction by recursive guillotine partition\n// ============================================================\n\nstruct Cand {\n    long double cost;\n    bool vertical;\n    int k;\n    int cut;\n};\n\nvoid split_rec(const vector<int>& ids, int L, int R, int B, int T,\n               vector<Rect>& leaf_box, bool randomized, long double shape_lambda) {\n    int m = (int)ids.size();\n    if (m == 1) {\n        leaf_box[ids[0]] = {L, B, R, T};\n        return;\n    }\n\n    long long sumR = 0;\n    for (int id : ids) sumR += Rr[id];\n\n    vector<int> sx = ids, sy = ids;\n    sort(sx.begin(), sx.end(), [&](int i, int j) { return X[i] < X[j]; });\n    sort(sy.begin(), sy.end(), [&](int i, int j) { return Y[i] < Y[j]; });\n\n    vector<Cand> cands;\n    cands.reserve(2 * (m - 1));\n\n    int W = R - L;\n    int H = T - B;\n\n    // Vertical\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sx[k - 1]];\n            int minC = X[sx[k - 1]] + 1;\n            int maxC = X[sx[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)L + (long double)W * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int w1 = cut - L;\n            int w2 = R - cut;\n            if (w1 <= 0 || w2 <= 0) continue;\n\n            long double desiredW = (long double)W * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)w1 - desiredW) / (long double)W;\n\n            long double shape = fabsl(log((long double)w1 / (long double)H))\n                              + fabsl(log((long double)w2 / (long double)H));\n\n            cands.push_back({err + shape_lambda * shape, true, k, cut});\n        }\n    }\n\n    // Horizontal\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sy[k - 1]];\n            int minC = Y[sy[k - 1]] + 1;\n            int maxC = Y[sy[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)B + (long double)H * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int h1 = cut - B;\n            int h2 = T - cut;\n            if (h1 <= 0 || h2 <= 0) continue;\n\n            long double desiredH = (long double)H * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)h1 - desiredH) / (long double)H;\n\n            long double shape = fabsl(log((long double)W / (long double)h1))\n                              + fabsl(log((long double)W / (long double)h2));\n\n            cands.push_back({err + shape_lambda * shape, false, k, cut});\n        }\n    }\n\n    if (cands.empty()) {\n        int k = m / 2;\n        int cut = max(X[sx[k - 1]] + 1, min(X[sx[k]], (L + R) / 2));\n        cut = max(L + 1, min(R - 1, cut));\n        vector<int> left(sx.begin(), sx.begin() + k);\n        vector<int> right(sx.begin() + k, sx.end());\n        split_rec(left, L, cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, cut, R, B, T, leaf_box, randomized, shape_lambda);\n        return;\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Cand& p, const Cand& q) {\n        return p.cost < q.cost;\n    });\n\n    int pick = 0;\n    if (randomized) {\n        int top = min<int>(6, cands.size());\n        vector<long long> w(top);\n        long long s = 0;\n        for (int i = 0; i < top; ++i) {\n            w[i] = top - i;\n            s += w[i];\n        }\n        long long z = (long long)(rng() % s);\n        int chosen = 0;\n        while (z >= w[chosen]) {\n            z -= w[chosen];\n            ++chosen;\n        }\n        pick = chosen;\n    }\n\n    Cand best = cands[pick];\n\n    if (best.vertical) {\n        vector<int> left(sx.begin(), sx.begin() + best.k);\n        vector<int> right(sx.begin() + best.k, sx.end());\n        split_rec(left, L, best.cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, best.cut, R, B, T, leaf_box, randomized, shape_lambda);\n    } else {\n        vector<int> down(sy.begin(), sy.begin() + best.k);\n        vector<int> up(sy.begin() + best.k, sy.end());\n        split_rec(down, L, R, B, best.cut, leaf_box, randomized, shape_lambda);\n        split_rec(up, L, R, best.cut, T, leaf_box, randomized, shape_lambda);\n    }\n}\n\nRect place_inside_box(const Rect& box, int id) {\n    int W = box.c - box.a;\n    int H = box.d - box.b;\n    long long boxA = 1LL * W * H;\n    long long target = Rr[id];\n\n    if (boxA <= target) return box;\n\n    long long bestA = -1;\n    int bestW = 1, bestH = 1;\n    long long bestShape = (1LL << 60);\n\n    for (int w = 1; w <= W; ++w) {\n        long long h = min<long long>(H, target / w);\n        if (h <= 0) continue;\n        long long a = 1LL * w * h;\n        long long shp = llabs((long long)w - h);\n        if (a > bestA || (a == bestA && shp < bestShape)) {\n            bestA = a;\n            bestW = w;\n            bestH = (int)h;\n            bestShape = shp;\n        }\n    }\n\n    int loA = max(box.a, X[id] + 1 - bestW);\n    int hiA = min(X[id], box.c - bestW);\n    int a = clamp(X[id] - bestW / 2, loA, hiA);\n    int c = a + bestW;\n\n    int loB = max(box.b, Y[id] + 1 - bestH);\n    int hiB = min(Y[id], box.d - bestH);\n    int b = clamp(Y[id] - bestH / 2, loB, hiB);\n    int d = b + bestH;\n\n    return {a, b, c, d};\n}\n\nvector<Rect> build_solution(bool randomized) {\n    vector<int> ids(n);\n    iota(ids.begin(), ids.end(), 0);\n\n    long double shape_lambda;\n    if (!randomized) {\n        shape_lambda = 0.0015L;\n    } else {\n        int t = (int)(rng() % 5);\n        if (t == 0) shape_lambda = 0.0L;\n        else if (t == 1) shape_lambda = 0.0006L;\n        else if (t == 2) shape_lambda = 0.0012L;\n        else if (t == 3) shape_lambda = 0.0020L;\n        else shape_lambda = 0.0035L;\n    }\n\n    vector<Rect> boxes(n);\n    split_rec(ids, 0, BOARD, 0, BOARD, boxes, randomized, shape_lambda);\n\n    vector<Rect> rects(n);\n    for (int i = 0; i < n; ++i) rects[i] = place_inside_box(boxes[i], i);\n    return rects;\n}\n\n// ============================================================\n// Cheap side-wise local hill climbing\n// ============================================================\n\nstruct Op {\n    double gain = 0.0;\n    Rect nr;\n};\n\nvector<int> candidate_steps(long long diff, int dim, int tmax) {\n    vector<int> cand;\n    cand.reserve(24);\n    cand.push_back(1);\n    cand.push_back(tmax);\n\n    long double q = (long double)diff / (long double)dim;\n    long long f = (long long)floor((double)q);\n    long long c = (long long)ceil((double)q);\n    for (int d = -3; d <= 3; ++d) {\n        cand.push_back((int)(f + d));\n        cand.push_back((int)(c + d));\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    vector<int> res;\n    for (int t : cand) if (1 <= t && t <= tmax) res.push_back(t);\n    return res;\n}\n\nOp best_operation_for(int i, const vector<Rect>& rects) {\n    const Rect& curR = rects[i];\n    long long s = area(curR);\n    long long target = Rr[i];\n    double curSat = sat(s, target);\n\n    Op best;\n    best.nr = curR;\n\n    int w = curR.c - curR.a;\n    int h = curR.d - curR.b;\n\n    if (s < target) {\n        // left expand\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].c <= curR.a) {\n                    bound = max(bound, rects[j].c);\n                }\n            }\n            int tmax = curR.a - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right expand\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].a >= curR.c) {\n                    bound = min(bound, rects[j].a);\n                }\n            }\n            int tmax = bound - curR.c;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down expand\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].d <= curR.b) {\n                    bound = max(bound, rects[j].d);\n                }\n            }\n            int tmax = curR.b - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up expand\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].b >= curR.d) {\n                    bound = min(bound, rects[j].b);\n                }\n            }\n            int tmax = bound - curR.d;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    if (s > target) {\n        // left shrink\n        {\n            int tmax = X[i] - curR.a;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right shrink\n        {\n            int tmax = curR.c - (X[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down shrink\n        {\n            int tmax = Y[i] - curR.b;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up shrink\n        {\n            int tmax = curR.d - (Y[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid side_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            double sc = local_score(rects[i], i);\n            double noise = (double)(rng() & 1023) * 1e-12;\n            ord.push_back({sc + noise, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        for (auto [_, i] : ord) {\n            if (timer.elapsed() >= end_time) break;\n            while (timer.elapsed() < end_time) {\n                Op op = best_operation_for(i, rects);\n                if (op.gain <= 1e-15) break;\n                rects[i] = op.nr;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Stronger exact single-rectangle re-optimization\n// ============================================================\n\nRect exact_best_for(int i, const vector<Rect>& rects) {\n    const Rect& cur = rects[i];\n    const long long target = Rr[i];\n    double bestSc = local_score(cur, i);\n    Rect best = cur;\n\n    vector<int> bottoms, tops;\n    bottoms.reserve(n + 8);\n    tops.reserve(n + 8);\n\n    bottoms.push_back(0);\n    bottoms.push_back(Y[i]);\n    bottoms.push_back(cur.b);\n\n    tops.push_back(BOARD);\n    tops.push_back(Y[i] + 1);\n    tops.push_back(cur.d);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        if (rects[j].d <= Y[i]) bottoms.push_back(rects[j].d);\n        if (rects[j].b > Y[i]) tops.push_back(rects[j].b);\n    }\n\n    sort(bottoms.begin(), bottoms.end());\n    bottoms.erase(unique(bottoms.begin(), bottoms.end()), bottoms.end());\n    sort(tops.begin(), tops.end());\n    tops.erase(unique(tops.begin(), tops.end()), tops.end());\n\n    auto try_rect = [&](int b, int d, int left, int right) {\n        if (!(b <= Y[i] && Y[i] < d)) return;\n        int H = d - b;\n        int maxW = right - left;\n        if (H <= 0 || maxW <= 0) return;\n\n        vector<int> ws;\n        ws.reserve(20);\n        ws.push_back(1);\n        ws.push_back(maxW);\n        ws.push_back(cur.c - cur.a);\n\n        long double ideal = (long double)target / (long double)H;\n        long long f = (long long)floor((double)ideal);\n        long long c = (long long)ceil((double)ideal);\n        for (int dt = -3; dt <= 3; ++dt) {\n            ws.push_back((int)(f + dt));\n            ws.push_back((int)(c + dt));\n        }\n\n        sort(ws.begin(), ws.end());\n        ws.erase(unique(ws.begin(), ws.end()), ws.end());\n\n        for (int w : ws) {\n            if (w < 1 || w > maxW) continue;\n\n            int loA = max(left, X[i] + 1 - w);\n            int hiA = min(X[i], right - w);\n            if (loA > hiA) continue;\n\n            int pref = cur.a;\n            if (pref < loA || pref > hiA) pref = X[i] - w / 2;\n            int a = clamp(pref, loA, hiA);\n            int c2 = a + w;\n\n            Rect cand{a, b, c2, d};\n            double sc = local_score(cand, i);\n\n            if (sc > bestSc + 1e-15) {\n                bestSc = sc;\n                best = cand;\n            } else if (fabs(sc - bestSc) <= 1e-15) {\n                long long da = llabs(area(cand) - target);\n                long long db = llabs(area(best) - target);\n                if (da < db) {\n                    best = cand;\n                } else if (da == db) {\n                    int moveCand = abs(cand.a - cur.a) + abs(cand.b - cur.b) + abs(cand.c - cur.c) + abs(cand.d - cur.d);\n                    int moveBest = abs(best.a - cur.a) + abs(best.b - cur.b) + abs(best.c - cur.c) + abs(best.d - cur.d);\n                    if (moveCand < moveBest) best = cand;\n                }\n            }\n        }\n    };\n\n    for (int b : bottoms) {\n        if (b > Y[i]) continue;\n        for (int d : tops) {\n            if (d <= Y[i] || b >= d) continue;\n\n            int left = 0, right = BOARD;\n            bool invalid = false;\n\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.d <= b || d <= o.b) continue; // no vertical overlap\n\n                if (o.a <= X[i] && X[i] < o.c) {\n                    invalid = true;\n                    break;\n                }\n                if (o.c <= X[i]) left = max(left, o.c);\n                else if (o.a > X[i]) right = min(right, o.a);\n            }\n            if (invalid || left >= right) continue;\n\n            try_rect(b, d, left, right);\n        }\n    }\n\n    return best;\n}\n\nvoid exact_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            ord.push_back({local_score(rects[i], i), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        int K = min(n, 24);\n\n        for (int z = 0; z < K; ++z) {\n            if (timer.elapsed() >= end_time) break;\n            int i = ord[z].second;\n\n            Rect nr = exact_best_for(i, rects);\n            if (local_score(nr, i) > local_score(rects[i], i) + 1e-15) {\n                rects[i] = nr;\n                changed = true;\n\n                // After a bigger reshape, a few cheap one-side tweaks often help.\n                while (timer.elapsed() < end_time) {\n                    Op op = best_operation_for(i, rects);\n                    if (op.gain <= 1e-15) break;\n                    rects[i] = op.nr;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid add_state(vector<State>& states, vector<Rect> rects) {\n    double sc = total_score(rects);\n    states.push_back({sc, std::move(rects)});\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)states.size() > 4) states.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    X.resize(n);\n    Y.resize(n);\n    Rr.resize(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> X[i] >> Y[i] >> Rr[i];\n    }\n\n    vector<State> states;\n    add_state(states, build_solution(false));\n\n    // Diversified initial solutions\n    double init_end = 0.75;\n    while (timer.elapsed() < init_end) {\n        add_state(states, build_solution(true));\n    }\n\n    // Cheap polishing for top candidates\n    double polish_end = 2.4;\n    for (int i = 0; i < (int)states.size(); ++i) {\n        double now = timer.elapsed();\n        if (now >= polish_end) break;\n        double slice = (polish_end - now) / (double)(states.size() - i);\n        side_improve(states[i].rects, now + slice);\n        states[i].score = total_score(states[i].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<Rect> best = states[0].rects;\n\n    // Stronger final optimization focused on difficult rectangles\n    exact_improve(best, 4.75);\n\n    // Final cheap cleanup\n    side_improve(best, TL);\n\n    for (int i = 0; i < n; ++i) {\n        cout << best[i].a << ' ' << best[i].b << ' ' << best[i].c << ' ' << best[i].d << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int C = N * N;\n    static constexpr double TL = 1.95;\n\n    int si, sj, start;\n    array<int, C> tile{};\n    array<int, C> val{};\n    array<array<int, 4>, C> adj{};\n    array<uint8_t, C> deg{};\n\n    int M = 0;\n\n    // tile info\n    vector<int> tileSize;\n    vector<int> tileSum;\n    vector<int> tileMax;\n    vector<int> tileExp2;   // heuristic expected contribution * 2\n    vector<int> tileUB;     // optimistic upper bound contribution\n\n    vector<unsigned char> vis;\n\n    vector<int> cellSeen;\n    vector<int> cellComp;\n    vector<int> tileSeen;\n    int evalStamp = 1;\n    int tileStamp = 1;\n    array<int, C> qbuf{};\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n\n    struct Params {\n        int wExp2;\n        int wUb;\n        int wTiles;\n        int wImm;\n        int wBranches;\n        int wDeg;\n        double q;\n        int exactLimit;\n    };\n\n    struct ReachInfo {\n        int selExp2 = 0;\n        int selUb = 0;\n        int selTiles = 0;\n\n        int maxUb = 0;\n        int maxTiles = 0;\n\n        int branches = 0;\n        int availDeg = 0;\n    };\n\n    struct Cand {\n        int to;\n        int eval;\n        int imm;\n        int exp2;\n        int ub;\n        int tiles;\n        int branches;\n        int availDeg;\n    };\n\n    struct Solution {\n        vector<int> seq;\n        vector<int> pref;\n        int score = 0;\n        uint64_t hash = 0;\n    };\n\n    vector<Solution> elite;\n    Solution bestSol;\n\n    // exact search state\n    vector<int> exactBestPath;\n    vector<int> exactCurPath;\n    int exactBestScore = 0;\n    bool exactAbort = false;\n    int exactNodes = 0;\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int r, int c) const { return r * N + c; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> si >> sj;\n        start = id(si, sj);\n\n        int mxTile = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int t;\n                cin >> t;\n                tile[id(r, c)] = t;\n                mxTile = max(mxTile, t);\n            }\n        }\n        M = mxTile + 1;\n\n        tileSize.assign(M, 0);\n        tileSum.assign(M, 0);\n        tileMax.assign(M, 0);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p;\n                cin >> p;\n                int v = id(r, c);\n                val[v] = p;\n                int t = tile[v];\n                tileSize[t]++;\n                tileSum[t] += p;\n                tileMax[t] = max(tileMax[t], p);\n            }\n        }\n\n        tileExp2.assign(M, 0);\n        tileUB.assign(M, 0);\n        for (int t = 0; t < M; t++) {\n            if (tileSize[t] == 1) {\n                tileExp2[t] = tileSum[t] * 2;\n                tileUB[t] = tileSum[t];\n            } else {\n                // heuristic: average contribution for domino in *2 scale\n                tileExp2[t] = tileSum[t];\n                tileUB[t] = tileMax[t];\n            }\n        }\n\n        // adjacency between cells of different tiles only\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                int d = 0;\n                const int dr[4] = {-1, 1, 0, 0};\n                const int dc[4] = {0, 0, -1, 1};\n                for (int k = 0; k < 4; k++) {\n                    int nr = r + dr[k], nc = c + dc[k];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    int u = id(nr, nc);\n                    if (tile[u] == tile[v]) continue;\n                    adj[v][d++] = u;\n                }\n                deg[v] = (uint8_t)d;\n            }\n        }\n\n        vis.assign(M, 0);\n        cellSeen.assign(C, 0);\n        cellComp.assign(C, -1);\n        tileSeen.assign(M, 0);\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : seq) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    bool cand_cmp(const Cand& a, const Cand& b) const {\n        if (a.eval != b.eval) return a.eval > b.eval;\n        if (a.tiles != b.tiles) return a.tiles > b.tiles;\n        if (a.exp2 != b.exp2) return a.exp2 > b.exp2;\n        if (a.imm != b.imm) return a.imm > b.imm;\n        if (a.branches != b.branches) return a.branches > b.branches;\n        return a.availDeg > b.availDeg;\n    }\n\n    Params sample_params() {\n        Params p;\n        p.wExp2 = rng.next_int(5, 8);\n        p.wUb = rng.next_int(1, 3);\n        p.wTiles = rng.next_int(50, 120);\n        p.wImm = rng.next_int(14, 24);\n        p.wBranches = rng.next_int(20, 90);\n        p.wDeg = rng.next_int(8, 28);\n        p.q = 0.05 + 0.25 * rng.next_double();\n\n        double e = elapsed();\n        if (e < 0.7) p.exactLimit = 22;\n        else if (e < 1.3) p.exactLimit = 20;\n        else p.exactLimit = 18;\n        return p;\n    }\n\n    inline int comp_metric(int exp2, int ub, int tiles, const Params& par) const {\n        return par.wExp2 * exp2 + par.wUb * ub + par.wTiles * tiles;\n    }\n\n    ReachInfo analyze_from_cell(int cell, const vector<unsigned char>& used, int forbidTile, const Params& par) {\n        ++evalStamp;\n\n        int compExp2[4];\n        int compUb[4];\n        int compTiles[4];\n        int compCnt = 0;\n\n        int branchIds[4];\n        int branchCnt = 0;\n\n        ReachInfo res;\n        int bestMetric = -1;\n\n        for (int i = 0; i < deg[cell]; i++) {\n            int s = adj[cell][i];\n            int ts = tile[s];\n            if (used[ts] || ts == forbidTile) continue;\n\n            res.availDeg++;\n\n            if (cellSeen[s] != evalStamp) {\n                int cid = compCnt++;\n                int qh = 0, qt = 0;\n                qbuf[qt++] = s;\n                cellSeen[s] = evalStamp;\n                cellComp[s] = cid;\n\n                ++tileStamp;\n                int exp2 = 0, ub = 0, tilesCnt = 0;\n\n                while (qh < qt) {\n                    int v = qbuf[qh++];\n                    int tv = tile[v];\n                    if (tileSeen[tv] != tileStamp) {\n                        tileSeen[tv] = tileStamp;\n                        exp2 += tileExp2[tv];\n                        ub += tileUB[tv];\n                        tilesCnt++;\n                    }\n                    for (int j = 0; j < deg[v]; j++) {\n                        int u = adj[v][j];\n                        int tu = tile[u];\n                        if (used[tu] || tu == forbidTile) continue;\n                        if (cellSeen[u] == evalStamp) continue;\n                        cellSeen[u] = evalStamp;\n                        cellComp[u] = cid;\n                        qbuf[qt++] = u;\n                    }\n                }\n\n                compExp2[cid] = exp2;\n                compUb[cid] = ub;\n                compTiles[cid] = tilesCnt;\n            }\n\n            int cid = cellComp[s];\n            int metric = comp_metric(compExp2[cid], compUb[cid], compTiles[cid], par);\n            if (metric > bestMetric ||\n                (metric == bestMetric && compTiles[cid] > res.selTiles) ||\n                (metric == bestMetric && compTiles[cid] == res.selTiles && compUb[cid] > res.selUb)) {\n                bestMetric = metric;\n                res.selExp2 = compExp2[cid];\n                res.selUb = compUb[cid];\n                res.selTiles = compTiles[cid];\n            }\n\n            res.maxUb = max(res.maxUb, compUb[cid]);\n            res.maxTiles = max(res.maxTiles, compTiles[cid]);\n\n            bool exists = false;\n            for (int b = 0; b < branchCnt; b++) {\n                if (branchIds[b] == cid) {\n                    exists = true;\n                    break;\n                }\n            }\n            if (!exists) branchIds[branchCnt++] = cid;\n        }\n\n        res.branches = branchCnt;\n        return res;\n    }\n\n    inline int candidate_eval(int imm, const ReachInfo& ri, const Params& par) const {\n        return par.wImm * imm\n             + par.wExp2 * ri.selExp2\n             + par.wUb * ri.selUb\n             + par.wTiles * ri.selTiles\n             + par.wBranches * ri.branches\n             + par.wDeg * ri.availDeg;\n    }\n\n    vector<int> greedy_suffix_small(int cur, vector<unsigned char> used, const Params& par, int& outScore) {\n        vector<int> path;\n        outScore = 0;\n\n        while (true) {\n            Cand cs[4];\n            int cc = 0;\n            for (int i = 0; i < deg[cur]; i++) {\n                int nx = adj[cur][i];\n                int tnx = tile[nx];\n                if (used[tnx]) continue;\n                ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n                int ev = candidate_eval(val[nx], ri, par);\n                cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n            }\n            if (cc == 0) break;\n            sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n            int nx = cs[0].to;\n            used[tile[nx]] = 1;\n            path.push_back(nx);\n            outScore += val[nx];\n            cur = nx;\n        }\n        return path;\n    }\n\n    void exact_dfs(int cur, vector<unsigned char>& used, int curScore, const Params& par) {\n        if ((++exactNodes & 1023) == 0) {\n            if (elapsed() > TL) {\n                exactAbort = true;\n                return;\n            }\n        }\n\n        ReachInfo ub = analyze_from_cell(cur, used, -1, par);\n        if (curScore + ub.maxUb <= exactBestScore) return;\n\n        Cand cs[4];\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            int tnx = tile[nx];\n            if (used[tnx]) continue;\n            ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n            int ev = candidate_eval(val[nx], ri, par);\n            cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n        }\n\n        if (cc == 0) {\n            if (curScore > exactBestScore) {\n                exactBestScore = curScore;\n                exactBestPath = exactCurPath;\n            }\n            return;\n        }\n\n        sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n\n        for (int i = 0; i < cc; i++) {\n            int nx = cs[i].to;\n            int tnx = tile[nx];\n            used[tnx] = 1;\n            exactCurPath.push_back(nx);\n            exact_dfs(nx, used, curScore + val[nx], par);\n            exactCurPath.pop_back();\n            used[tnx] = 0;\n            if (exactAbort) return;\n        }\n    }\n\n    vector<int> exact_finish(int cur, vector<unsigned char>& used, const Params& par) {\n        exactAbort = false;\n        exactNodes = 0;\n        exactBestPath.clear();\n        exactCurPath.clear();\n        exactBestScore = 0;\n\n        // strong initial lower bound\n        int greedyScore = 0;\n        exactBestPath = greedy_suffix_small(cur, used, par, greedyScore);\n        exactBestScore = greedyScore;\n\n        exact_dfs(cur, used, 0, par);\n        return exactBestPath;\n    }\n\n    void build_prefix_state(const Solution& base, int cutIdx, vector<int>& seq, int& score) {\n        fill(vis.begin(), vis.end(), 0);\n        seq.clear();\n        seq.reserve(C);\n        score = 0;\n\n        for (int i = 0; i <= cutIdx; i++) {\n            int v = base.seq[i];\n            seq.push_back(v);\n            vis[tile[v]] = 1;\n        }\n        score = base.pref[cutIdx];\n    }\n\n    pair<vector<int>, int> grow_from(const Solution& base, int cutIdx, const Params& par) {\n        vector<int> seq;\n        int score = 0;\n        build_prefix_state(base, cutIdx, seq, score);\n\n        int cur = seq.back();\n\n        while (true) {\n            ReachInfo curInfo = analyze_from_cell(cur, vis, -1, par);\n            if (curInfo.maxTiles <= par.exactLimit) {\n                vector<int> suf = exact_finish(cur, vis, par);\n                for (int nx : suf) {\n                    vis[tile[nx]] = 1;\n                    seq.push_back(nx);\n                    score += val[nx];\n                    cur = nx;\n                }\n                break;\n            }\n\n            Cand cs[4];\n            int cc = 0;\n            for (int i = 0; i < deg[cur]; i++) {\n                int nx = adj[cur][i];\n                int tnx = tile[nx];\n                if (vis[tnx]) continue;\n\n                ReachInfo ri = analyze_from_cell(nx, vis, tnx, par);\n                int ev = candidate_eval(val[nx], ri, par);\n                cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n            }\n\n            if (cc == 0) break;\n            sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n\n            int pick = 0;\n            if (cc >= 2) {\n                int gap = cs[0].eval - cs[1].eval;\n                double q = par.q;\n                if (gap > 3000) q *= 0.08;\n                else if (gap > 1500) q *= 0.20;\n                else if (gap > 700) q *= 0.40;\n                else if (gap > 300) q *= 0.70;\n                else q *= 1.10;\n                if (q > 0.80) q = 0.80;\n\n                while (pick + 1 < cc && rng.next_double() < q) pick++;\n            }\n\n            int nx = cs[pick].to;\n            vis[tile[nx]] = 1;\n            seq.push_back(nx);\n            score += val[nx];\n            cur = nx;\n        }\n\n        return {seq, score};\n    }\n\n    Solution make_solution(const vector<int>& seq, int score) {\n        Solution s;\n        s.seq = seq;\n        s.score = score;\n        s.pref.resize(seq.size());\n        int sum = 0;\n        for (int i = 0; i < (int)seq.size(); i++) {\n            sum += val[seq[i]];\n            s.pref[i] = sum;\n        }\n        s.hash = hash_seq(seq);\n        return s;\n    }\n\n    void add_solution(const vector<int>& seq, int score) {\n        Solution sol = make_solution(seq, score);\n\n        if (bestSol.seq.empty() || score > bestSol.score) {\n            bestSol = sol;\n        }\n\n        for (auto& e : elite) {\n            if (e.hash == sol.hash) {\n                if (sol.score > e.score) e = sol;\n                return;\n            }\n        }\n\n        elite.push_back(sol);\n        sort(elite.begin(), elite.end(), [](const Solution& a, const Solution& b) {\n            return a.score > b.score;\n        });\n        if ((int)elite.size() > 6) elite.resize(6);\n    }\n\n    const Solution& choose_parent() {\n        if (elite.empty()) return bestSol;\n        double r = rng.next_double();\n        if (elite.size() == 1) return elite[0];\n        if (r < 0.45) return elite[0];\n        if (r < 0.70) return elite[min<int>(1, elite.size() - 1)];\n        if (r < 0.88) return elite[rng.next_int(0, min<int>(2, elite.size() - 1))];\n        return elite[rng.next_int(0, (int)elite.size() - 1)];\n    }\n\n    int choose_cut(const Solution& base) {\n        int L = (int)base.seq.size() - 1; // moves\n        if (L <= 0) return 0;\n        int maxCut = L - 1; // force actual regrowth when possible\n        if (maxCut <= 0) return 0;\n\n        uint32_t mode = rng.next_u32() % 6;\n        int cut = 0;\n        if (mode == 0) {\n            cut = 0;\n        } else if (mode == 1) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u * u); // early mutation\n        } else if (mode == 2) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u); // uniform\n        } else if (mode == 3) {\n            double u = rng.next_double();\n            cut = maxCut - (int)(maxCut * u * u); // suffix tuning\n        } else {\n            // around middle / late\n            int lo = max(0, maxCut / 3);\n            int hi = maxCut;\n            cut = rng.next_int(lo, hi);\n        }\n        if (cut < 0) cut = 0;\n        if (cut > maxCut) cut = maxCut;\n        return cut;\n    }\n\n    string seq_to_answer(const vector<int>& seq) {\n        string ans;\n        ans.reserve(max(0, (int)seq.size() - 1));\n        for (int i = 1; i < (int)seq.size(); i++) {\n            int a = seq[i - 1], b = seq[i];\n            if (b == a - N) ans.push_back('U');\n            else if (b == a + N) ans.push_back('D');\n            else if (b == a - 1) ans.push_back('L');\n            else ans.push_back('R');\n        }\n        return ans;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        // initial trivial solution\n        bestSol = make_solution(vector<int>{start}, val[start]);\n        elite.clear();\n        elite.push_back(bestSol);\n\n        // a few full restarts first\n        for (int rep = 0; rep < 6 && elapsed() < 0.15; rep++) {\n            Params par = sample_params();\n            auto [seq, score] = grow_from(bestSol, 0, par);\n            add_solution(seq, score);\n        }\n\n        while (elapsed() < TL) {\n            Params par = sample_params();\n\n            bool doRestart = elite.empty() || rng.next_double() < 0.12;\n            if (doRestart) {\n                auto [seq, score] = grow_from(bestSol, 0, par); // bestSol[0] is start\n                add_solution(seq, score);\n                continue;\n            }\n\n            const Solution& base = choose_parent();\n            int cut = choose_cut(base);\n            auto [seq, score] = grow_from(base, cut, par);\n            add_solution(seq, score);\n        }\n\n        cout << seq_to_answer(bestSol.seq) << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horizontal; // true: h[i][j], false: v[i][j]\n    int i, j;\n};\n\nstruct Sample {\n    double y = 0.0;\n    // hp[row][k] = number of horizontal edges on row=row with edge-index < k used by the path\n    // k in [0,29], total on row is hp[row][29]\n    array<array<unsigned char, 30>, 30> hp{};\n    // vp[col][k] = number of vertical edges on col=col with edge-index < k used by the path\n    // k in [0,29], total on col is vp[col][29]\n    array<array<unsigned char, 30>, 30> vp{};\n};\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr double PRIOR = 5000.0;\n\n    vector<Sample> samples;\n\n    // Global model\n    int splitH[N], splitV[N];     // row split / column split, in [1,28]\n    double A[N], B[N];            // horizontal row params: left/right\n    double C[N], D[N];            // vertical col params: upper/lower\n\n    // Local per-edge estimates\n    double edgeH[N][N - 1];\n    double edgeV[N - 1][N];\n    int cntH[N][N - 1];\n    int cntV[N - 1][N];\n\n    static double clamp_cost(double x) {\n        if (x < 1000.0) return 1000.0;\n        if (x > 9000.0) return 9000.0;\n        return x;\n    }\n\n    bool need_rebuild(int turn) const {\n        if (turn == 0) return true;\n        if (turn < 60) return turn % 5 == 0;\n        if (turn < 200) return turn % 10 == 0;\n        return turn % 20 == 0;\n    }\n\n    double global_h(int i, int j) const {\n        return (j < splitH[i] ? A[i] : B[i]);\n    }\n    double global_v(int i, int j) const {\n        return (i < splitV[j] ? C[j] : D[j]);\n    }\n\n    double route_h(int i, int j) const {\n        double g = global_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return g;\n        double w = (double)c / (c + 6.0);\n        return clamp_cost(g + w * (edgeH[i][j] - g));\n    }\n    double route_v(int i, int j) const {\n        double g = global_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return g;\n        double w = (double)c / (c + 6.0);\n        return clamp_cost(g + w * (edgeV[i][j] - g));\n    }\n\n    double prior_est_h(int i, int j) const {\n        return cntH[i][j] ? edgeH[i][j] : global_h(i, j);\n    }\n    double prior_est_v(int i, int j) const {\n        return cntV[i][j] ? edgeV[i][j] : global_v(i, j);\n    }\n\n    void rebuild_avg_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                A[i] = B[i] = PRIOR;\n                C[i] = D[i] = PRIOR;\n            }\n            return;\n        }\n\n        double Rh[N], Cv[N];\n        for (int i = 0; i < N; i++) {\n            Rh[i] = clamp_cost((A[i] + B[i]) * 0.5);\n            Cv[i] = clamp_cost((C[i] + D[i]) * 0.5);\n        }\n\n        vector<double> pred(m, 0.0);\n        auto rebuild_pred = [&]() {\n            fill(pred.begin(), pred.end(), 0.0);\n            for (int n = 0; n < m; n++) {\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (int)samples[n].hp[i][29] * Rh[i];\n                for (int j = 0; j < N; j++) s += (int)samples[n].vp[j][29] * Cv[j];\n                pred[n] = s;\n            }\n        };\n        rebuild_pred();\n\n        double lambda = 30.0 / sqrt((double)m + 1.0) + 1.0;\n\n        for (int it = 0; it < 8; it++) {\n            for (int i = 0; i < N; i++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].hp[i][29];\n                    if (f == 0.0) continue;\n                    num += f * (samples[n].y - pred[n] + Rh[i] * f);\n                    den += f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - Rh[i];\n                if (fabs(delta) > 1e-12) {\n                    Rh[i] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].hp[i][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].vp[j][29];\n                    if (f == 0.0) continue;\n                    num += f * (samples[n].y - pred[n] + Cv[j] * f);\n                    den += f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - Cv[j];\n                if (fabs(delta) > 1e-12) {\n                    Cv[j] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].vp[j][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            A[i] = B[i] = Rh[i];\n            C[i] = D[i] = Cv[i];\n        }\n    }\n\n    void compute_pred_split(vector<double>& pred) const {\n        int m = (int)samples.size();\n        pred.assign(m, 0.0);\n        for (int n = 0; n < m; n++) {\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)samples[n].hp[i][splitH[i]];\n                int t = (int)samples[n].hp[i][29];\n                s += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)samples[n].vp[j][splitV[j]];\n                int t = (int)samples[n].vp[j][29];\n                s += u * C[j] + (t - u) * D[j];\n            }\n            pred[n] = s;\n        }\n    }\n\n    void cd_update_param(double& param, vector<double>& pred, double lambda, const function<int(const Sample&)>& feat) {\n        int m = (int)samples.size();\n        double num = 0.0, den = 0.0;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f == 0.0) continue;\n            num += f * (samples[n].y - pred[n] + param * f);\n            den += f * f;\n        }\n        double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n        double delta = nv - param;\n        if (fabs(delta) <= 1e-12) return;\n        param = nv;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f) pred[n] += delta * f;\n        }\n    }\n\n    void fit_fixed_splits(vector<double>& pred, double lambda, int iters) {\n        int m = (int)samples.size();\n        if (m == 0) return;\n        compute_pred_split(pred);\n\n        for (int it = 0; it < iters; it++) {\n            for (int i = 0; i < N; i++) {\n                int sp = splitH[i];\n                cd_update_param(A[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    return (int)s.hp[i][sp];\n                });\n                cd_update_param(B[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    int l = (int)s.hp[i][sp];\n                    int t = (int)s.hp[i][29];\n                    return t - l;\n                });\n            }\n            for (int j = 0; j < N; j++) {\n                int sp = splitV[j];\n                cd_update_param(C[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    return (int)s.vp[j][sp];\n                });\n                cd_update_param(D[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    int u = (int)s.vp[j][sp];\n                    int t = (int)s.vp[j][29];\n                    return t - u;\n                });\n            }\n        }\n    }\n\n    void optimize_row_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int i = 0; i < N; i++) {\n            int oldsp = splitH[i];\n            double oldA = A[i], oldB = B[i];\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int tot = (int)samples[n].hp[i][29];\n                int oldr = tot - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double bestLoss = 1e300;\n            int bestSp = oldsp;\n            double bestA = oldA, bestB = oldB;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double r = base[n];\n                    int a = (int)samples[n].hp[i][sp];\n                    int t = (int)samples[n].hp[i][29];\n                    int b = t - a;\n                    aa += 1.0 * a * a;\n                    ab += 1.0 * a * b;\n                    bb += 1.0 * b * b;\n                    ar += a * r;\n                    br += b * r;\n                    rr += r * r;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double na = PRIOR, nb = PRIOR;\n                if (det > 1e-9) {\n                    na = (R0 * M11 - R1 * M01) / det;\n                    nb = (R1 * M00 - R0 * M01) / det;\n                }\n                na = clamp_cost(na);\n                nb = clamp_cost(nb);\n\n                double loss =\n                    rr\n                    - 2.0 * na * ar - 2.0 * nb * br\n                    + na * na * aa + 2.0 * na * nb * ab + nb * nb * bb\n                    + lambda * ((na - PRIOR) * (na - PRIOR) + (nb - PRIOR) * (nb - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestA = na;\n                    bestB = nb;\n                }\n            }\n\n            splitH[i] = bestSp;\n            A[i] = bestA;\n            B[i] = bestB;\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int oldt = (int)samples[n].hp[i][29];\n                int oldr = oldt - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n\n                int newl = (int)samples[n].hp[i][bestSp];\n                int newr = oldt - newl;\n                double newc = newl * bestA + newr * bestB;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void optimize_col_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int j = 0; j < N; j++) {\n            int oldsp = splitV[j];\n            double oldC = C[j], oldD = D[j];\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int tot = (int)samples[n].vp[j][29];\n                int oldd = tot - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double bestLoss = 1e300;\n            int bestSp = oldsp;\n            double bestC = oldC, bestD = oldD;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double r = base[n];\n                    int a = (int)samples[n].vp[j][sp];\n                    int t = (int)samples[n].vp[j][29];\n                    int b = t - a;\n                    aa += 1.0 * a * a;\n                    ab += 1.0 * a * b;\n                    bb += 1.0 * b * b;\n                    ar += a * r;\n                    br += b * r;\n                    rr += r * r;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double nc = PRIOR, nd = PRIOR;\n                if (det > 1e-9) {\n                    nc = (R0 * M11 - R1 * M01) / det;\n                    nd = (R1 * M00 - R0 * M01) / det;\n                }\n                nc = clamp_cost(nc);\n                nd = clamp_cost(nd);\n\n                double loss =\n                    rr\n                    - 2.0 * nc * ar - 2.0 * nd * br\n                    + nc * nc * aa + 2.0 * nc * nd * ab + nd * nd * bb\n                    + lambda * ((nc - PRIOR) * (nc - PRIOR) + (nd - PRIOR) * (nd - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestC = nc;\n                    bestD = nd;\n                }\n            }\n\n            splitV[j] = bestSp;\n            C[j] = bestC;\n            D[j] = bestD;\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int oldt = (int)samples[n].vp[j][29];\n                int oldd = oldt - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n\n                int newu = (int)samples[n].vp[j][bestSp];\n                int newd = oldt - newu;\n                double newc = newu * bestC + newd * bestD;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void rebuild_split_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                A[i] = B[i] = PRIOR;\n                C[i] = D[i] = PRIOR;\n            }\n            return;\n        }\n\n        double lambda = 12.0 / sqrt((double)m + 1.0) + 0.8;\n        vector<double> pred;\n\n        fit_fixed_splits(pred, lambda, 4);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n        fit_fixed_splits(pred, lambda, 3);\n    }\n\n    void rebuild_model() {\n        int m = (int)samples.size();\n\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = C[i] = D[i] = PRIOR;\n            }\n            return;\n        }\n\n        if (m < 80) {\n            rebuild_avg_model();\n        } else {\n            rebuild_split_model();\n        }\n    }\n\n    string shortest_path(int si, int sj, int ti, int tj) const {\n        static constexpr double INF = 1e100;\n        const int V = N * N;\n\n        auto id = [&](int x, int y) { return x * N + y; };\n\n        vector<double> dist(V, INF);\n        vector<int> par(V, -1);\n        vector<char> mv(V, 0);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        int s = id(si, sj);\n        int t = id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == t) break;\n\n            int x = u / N;\n            int y = u % N;\n\n            auto relax = [&](int nx, int ny, double w, char c) {\n                int v = id(nx, ny);\n                double nd = d + w;\n                if (nd + 1e-12 < dist[v]) {\n                    dist[v] = nd;\n                    par[v] = u;\n                    mv[v] = c;\n                    pq.push({nd, v});\n                }\n            };\n\n            if (x > 0)     relax(x - 1, y, route_v(x - 1, y), 'U');\n            if (x + 1 < N) relax(x + 1, y, route_v(x, y), 'D');\n            if (y > 0)     relax(x, y - 1, route_h(x, y - 1), 'L');\n            if (y + 1 < N) relax(x, y + 1, route_h(x, y), 'R');\n        }\n\n        string path;\n        for (int cur = t; cur != s; cur = par[cur]) path.push_back(mv[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    void build_sample_and_edges(int si, int sj, const string& path, Sample& smp, vector<EdgeRef>& edges) const {\n        bool hused[N][N - 1] = {};\n        bool vused[N - 1][N] = {};\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                vused[x - 1][y] = true;\n                edges.push_back({false, x - 1, y});\n                --x;\n            } else if (c == 'D') {\n                vused[x][y] = true;\n                edges.push_back({false, x, y});\n                ++x;\n            } else if (c == 'L') {\n                hused[x][y - 1] = true;\n                edges.push_back({true, x, y - 1});\n                --y;\n            } else if (c == 'R') {\n                hused[x][y] = true;\n                edges.push_back({true, x, y});\n                ++y;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            smp.hp[i][0] = 0;\n            for (int j = 0; j < N - 1; j++) {\n                smp.hp[i][j + 1] = smp.hp[i][j] + (hused[i][j] ? 1 : 0);\n            }\n        }\n        for (int j = 0; j < N; j++) {\n            smp.vp[j][0] = 0;\n            for (int i = 0; i < N - 1; i++) {\n                smp.vp[j][i + 1] = smp.vp[j][i] + (vused[i][j] ? 1 : 0);\n            }\n        }\n    }\n\n    void update_local_edges(const vector<EdgeRef>& edges, double observed, int turn) {\n        if (edges.empty()) return;\n\n        vector<double> gains(edges.size());\n        double pred = 0.0, gsum = 0.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            if (e.horizontal) {\n                pred += prior_est_h(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntH[e.i][e.j] + 1.0);\n            } else {\n                pred += prior_est_v(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntV[e.i][e.j] + 1.0);\n            }\n            gsum += gains[k];\n        }\n\n        double residual = observed - pred;\n        double eta;\n        if (turn < 80) eta = 0.45;\n        else if (turn < 250) eta = 0.32;\n        else eta = 0.24;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            double delta = eta * residual * gains[k] / gsum;\n            delta = max(-1200.0, min(1200.0, delta));\n\n            if (e.horizontal) {\n                if (cntH[e.i][e.j] == 0) edgeH[e.i][e.j] = global_h(e.i, e.j);\n                edgeH[e.i][e.j] = clamp_cost(edgeH[e.i][e.j] + delta);\n                cntH[e.i][e.j]++;\n            } else {\n                if (cntV[e.i][e.j] == 0) edgeV[e.i][e.j] = global_v(e.i, e.j);\n                edgeV[e.i][e.j] = clamp_cost(edgeV[e.i][e.j] + delta);\n                cntV[e.i][e.j]++;\n            }\n        }\n    }\n\npublic:\n    Solver() {\n        for (int i = 0; i < N; i++) {\n            splitH[i] = splitV[i] = 15;\n            A[i] = B[i] = C[i] = D[i] = PRIOR;\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                edgeH[i][j] = PRIOR;\n                cntH[i][j] = 0;\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                edgeV[i][j] = PRIOR;\n                cntV[i][j] = 0;\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int turn = 0; turn < 1000; turn++) {\n            if (need_rebuild(turn)) rebuild_model();\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            string path = shortest_path(si, sj, ti, tj);\n\n            cout << path << '\\n';\n            cout.flush();\n\n            long long feedback;\n            cin >> feedback;\n\n            Sample smp;\n            smp.y = (double)feedback;\n            vector<EdgeRef> edges;\n            build_sample_and_edges(si, sj, path, smp, edges);\n\n            samples.push_back(smp);\n            update_local_edges(edges, (double)feedback, turn);\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAXL = 12;\nstatic constexpr int MINL = 2;\nstatic constexpr int WORDS = 13; // ceil(800/64)\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\nstatic inline int ch2v(char c) { return c - 'A'; }\nstatic inline char v2ch(int v) { return char('A' + v); }\n\ntemplate<class Bits>\nstatic inline bool getbit(const Bits& b, int i) {\n    return (b[i >> 6] >> (i & 63)) & 1ULL;\n}\ntemplate<class Bits>\nstatic inline void setbit(Bits& b, int i) {\n    b[i >> 6] |= 1ULL << (i & 63);\n}\n\nusing Bits = array<uint64_t, WORDS>;\n\nstruct Pattern {\n    int len;\n    uint64_t code;\n    int weight;\n    string s;\n};\n\nstruct ACNode {\n    array<int, 8> next{};\n    int link = 0;\n    vector<int> out;\n    ACNode() { next.fill(-1); }\n};\n\nstruct BeamState {\n    int node = 0;\n    int score = 0;\n    Bits seen{};\n    array<uint8_t, N> s{};\n};\n\nstruct MatrixState {\n    array<array<uint8_t, N>, N> a{};\n    array<Bits, N> row_bits{};\n    array<Bits, N> col_bits{};\n    vector<int> cnt; // number of lines covering pattern\n    int score = 0;   // weighted covered count\n};\n\nstruct Solver {\n    int M;\n    int K = 0;\n    vector<Pattern> pats;\n    vector<int> orig_weight;\n    array<unordered_map<uint64_t, int>, MAXL + 1> id_of;\n    vector<ACNode> ac;\n    mt19937_64 rng;\n    Timer timer;\n\n    Solver() : rng(chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    uint64_t encode_string(const string& s) {\n        uint64_t code = 0;\n        for (char c : s) code = (code << 3) | (uint64_t)ch2v(c);\n        return code;\n    }\n\n    string decode_string(uint64_t code, int len) {\n        string s(len, 'A');\n        for (int i = len - 1; i >= 0; --i) {\n            s[i] = v2ch(int(code & 7ULL));\n            code >>= 3;\n        }\n        return s;\n    }\n\n    void add_pattern_to_ac(const string& s, int id) {\n        int v = 0;\n        for (char c : s) {\n            int x = ch2v(c);\n            if (ac[v].next[x] == -1) {\n                ac[v].next[x] = (int)ac.size();\n                ac.emplace_back();\n            }\n            v = ac[v].next[x];\n        }\n        ac[v].out.push_back(id);\n    }\n\n    void build_ac() {\n        ac.clear();\n        ac.emplace_back();\n        for (int id = 0; id < K; ++id) add_pattern_to_ac(pats[id].s, id);\n\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = ac[0].next[c];\n            if (u == -1) ac[0].next[c] = 0;\n            else {\n                ac[u].link = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            int lk = ac[v].link;\n            if (!ac[lk].out.empty()) {\n                auto &dst = ac[v].out;\n                auto &src = ac[lk].out;\n                dst.insert(dst.end(), src.begin(), src.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = ac[v].next[c];\n                if (u == -1) ac[v].next[c] = ac[lk].next[c];\n                else {\n                    ac[u].link = ac[lk].next[c];\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    Bits compute_bits_seq(const uint8_t seq[N]) const {\n        Bits bits{};\n        bits.fill(0);\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                code = (code << 3) | (uint64_t)seq[(st + len - 1) % N];\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) setbit(bits, it->second);\n                }\n            }\n        }\n        return bits;\n    }\n\n    Bits compute_row_bits(const MatrixState& ms, int r) const {\n        uint8_t seq[N];\n        for (int c = 0; c < N; ++c) seq[c] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    Bits compute_col_bits(const MatrixState& ms, int c) const {\n        uint8_t seq[N];\n        for (int r = 0; r < N; ++r) seq[r] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    int row_gain_and_bits(const array<uint8_t, N>& row, const vector<int>& weight, Bits& bits) const {\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        bits = compute_bits_seq(seq);\n        int gain = 0;\n        for (int id = 0; id < K; ++id) if (getbit(bits, id)) gain += weight[id];\n        return gain;\n    }\n\n    array<uint8_t, N> fallback_row(const vector<int>& residual) {\n        int best_id = -1, best_key = -1;\n        for (int i = 0; i < K; ++i) {\n            int key = residual[i] * pats[i].len;\n            if (key > best_key) best_key = key, best_id = i;\n        }\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n        if (best_id != -1) {\n            const string& s = pats[best_id].s;\n            for (int i = 0; i < (int)s.size(); ++i) row[i] = ch2v(s[i]);\n        }\n        return row;\n    }\n\n    array<uint8_t, N> beam_search_row(const vector<int>& residual, const vector<uint8_t>& prefix) {\n        static constexpr int BEAM = 160;\n        static constexpr int FINAL_CAND = 24;\n\n        if ((int)prefix.size() > N) return fallback_row(residual);\n\n        vector<BeamState> beam(1);\n        beam[0].node = 0;\n        beam[0].score = 0;\n        beam[0].seen.fill(0);\n\n        int pos = 0;\n        for (uint8_t c : prefix) {\n            beam[0].s[pos++] = c;\n            beam[0].node = ac[beam[0].node].next[c];\n            for (int id : ac[beam[0].node].out) {\n                if (residual[id] > 0 && !getbit(beam[0].seen, id)) {\n                    setbit(beam[0].seen, id);\n                    beam[0].score += residual[id];\n                }\n            }\n        }\n\n        for (int d = pos; d < N; ++d) {\n            vector<BeamState> cand;\n            cand.reserve(beam.size() * 8);\n            for (const auto& st : beam) {\n                for (int c = 0; c < 8; ++c) {\n                    BeamState ns = st;\n                    ns.s[d] = (uint8_t)c;\n                    ns.node = ac[st.node].next[c];\n                    for (int id : ac[ns.node].out) {\n                        if (residual[id] > 0 && !getbit(ns.seen, id)) {\n                            setbit(ns.seen, id);\n                            ns.score += residual[id];\n                        }\n                    }\n                    cand.push_back(std::move(ns));\n                }\n            }\n            auto cmp = [](const BeamState& a, const BeamState& b) {\n                return a.score > b.score;\n            };\n            if ((int)cand.size() > BEAM) {\n                nth_element(cand.begin(), cand.begin() + BEAM, cand.end(), cmp);\n                cand.resize(BEAM);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n            beam.swap(cand);\n        }\n\n        array<uint8_t, N> best_row{};\n        int best_gain = -1;\n        int take = min<int>(FINAL_CAND, beam.size());\n        for (int i = 0; i < take; ++i) {\n            Bits bits{};\n            int gain = row_gain_and_bits(beam[i].s, residual, bits);\n            if (gain > best_gain) {\n                best_gain = gain;\n                best_row = beam[i].s;\n            }\n        }\n        if (best_gain <= 0) return fallback_row(residual);\n        return best_row;\n    }\n\n    vector<int> pick_seed_patterns(const vector<int>& residual, int lim = 6) {\n        vector<pair<int,int>> v;\n        v.reserve(K);\n        for (int i = 0; i < K; ++i) {\n            if (residual[i] <= 0) continue;\n            int key = residual[i] * pats[i].len;\n            v.push_back({key, i});\n        }\n        if ((int)v.size() > lim) {\n            nth_element(v.begin(), v.begin() + lim, v.end(),\n                        [](auto& a, auto& b){ return a.first > b.first; });\n            v.resize(lim);\n        }\n        sort(v.begin(), v.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> res;\n        for (auto &p : v) res.push_back(p.second);\n        return res;\n    }\n\n    vector<array<uint8_t, N>> build_initial_rows() {\n        vector<array<uint8_t, N>> rows;\n        vector<int> residual = orig_weight;\n\n        for (int r = 0; r < N; ++r) {\n            int rem = 0;\n            for (int x : residual) rem += x;\n            if (rem == 0) break;\n\n            vector<array<uint8_t, N>> candidates;\n            candidates.reserve(10);\n\n            // seedless beam\n            candidates.push_back(beam_search_row(residual, {}));\n\n            // seeded beams\n            auto seeds = pick_seed_patterns(residual, 6);\n            for (int id : seeds) {\n                vector<uint8_t> pref;\n                pref.reserve(pats[id].len);\n                for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                candidates.push_back(beam_search_row(residual, pref));\n            }\n\n            // choose best by uncovered gain\n            int best_gain = -1;\n            array<uint8_t, N> best_row{};\n            Bits best_bits{};\n            for (auto& row : candidates) {\n                Bits bits{};\n                int gain = row_gain_and_bits(row, residual, bits);\n                if (gain > best_gain) {\n                    best_gain = gain;\n                    best_row = row;\n                    best_bits = bits;\n                }\n            }\n            if (best_gain <= 0) {\n                best_row = fallback_row(residual);\n                row_gain_and_bits(best_row, residual, best_bits);\n            }\n\n            rows.push_back(best_row);\n            for (int id = 0; id < K; ++id) {\n                if (getbit(best_bits, id)) residual[id] = 0;\n            }\n        }\n\n        while ((int)rows.size() < N) {\n            array<uint8_t, N> row{};\n            for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n            rows.push_back(row);\n        }\n        return rows;\n    }\n\n    void init_matrix_state(MatrixState& ms, const vector<array<uint8_t, N>>& rows) {\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ms.a[r][c] = rows[r][c];\n\n        for (int r = 0; r < N; ++r) ms.row_bits[r] = compute_row_bits(ms, r);\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = compute_col_bits(ms, c);\n\n        ms.cnt.assign(K, 0);\n        ms.score = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int id = 0; id < K; ++id) {\n                if (getbit(ms.row_bits[r], id)) ms.cnt[id]++;\n            }\n        }\n        for (int c = 0; c < N; ++c) {\n            for (int id = 0; id < K; ++id) {\n                if (getbit(ms.col_bits[c], id)) ms.cnt[id]++;\n            }\n        }\n        for (int id = 0; id < K; ++id) if (ms.cnt[id] > 0) ms.score += orig_weight[id];\n    }\n\n    int calc_delta_two(const MatrixState& ms, const Bits& old1, const Bits& new1,\n                       const Bits& old2, const Bits& new2) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before - (int)getbit(old1, id) - (int)getbit(old2, id)\n                              + (int)getbit(new1, id) + (int)getbit(new2, id);\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_two(MatrixState& ms, const Bits& old1, const Bits& new1,\n                   const Bits& old2, const Bits& new2) {\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before - (int)getbit(old1, id) - (int)getbit(old2, id)\n                              + (int)getbit(new1, id) + (int)getbit(new2, id);\n            ms.cnt[id] = after;\n        }\n    }\n\n    int delta_many(const MatrixState& ms, const vector<Bits>& olds, const vector<Bits>& news) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int i = 0; i < (int)olds.size(); ++i) {\n                after -= (int)getbit(olds[i], id);\n                after += (int)getbit(news[i], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_many(MatrixState& ms, const vector<Bits>& olds, const vector<Bits>& news) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int i = 0; i < (int)olds.size(); ++i) {\n                after -= (int)getbit(olds[i], id);\n                after += (int)getbit(news[i], id);\n            }\n            ms.cnt[id] = after;\n        }\n    }\n\n    int eval_row_rotate(const MatrixState& ms, int r, int sh, array<Bits, N>& new_cols) const {\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                seq[i] = (i == r ? ms.a[r][(c + sh) % N] : ms.a[i][c]);\n            }\n            new_cols[c] = compute_bits_seq(seq);\n            olds.push_back(ms.col_bits[c]);\n            news.push_back(new_cols[c]);\n        }\n        return delta_many(ms, olds, news);\n    }\n\n    void apply_row_rotate(MatrixState& ms, int r, int sh, const array<Bits, N>& new_cols, int delta) {\n        array<uint8_t, N> old = ms.a[r], nw{};\n        for (int c = 0; c < N; ++c) nw[c] = old[(c + sh) % N];\n        ms.a[r] = nw;\n\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int c = 0; c < N; ++c) {\n            olds.push_back(ms.col_bits[c]);\n            news.push_back(new_cols[c]);\n            ms.col_bits[c] = new_cols[c];\n        }\n        apply_many(ms, olds, news);\n        ms.score += delta;\n        // row_bits[r] unchanged by cyclic rotation\n    }\n\n    int eval_row_swap(const MatrixState& ms, int r1, int r2, array<Bits, N>& new_cols) const {\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                if (i == r1) seq[i] = ms.a[r2][c];\n                else if (i == r2) seq[i] = ms.a[r1][c];\n                else seq[i] = ms.a[i][c];\n            }\n            new_cols[c] = compute_bits_seq(seq);\n            olds.push_back(ms.col_bits[c]);\n            news.push_back(new_cols[c]);\n        }\n        return delta_many(ms, olds, news);\n    }\n\n    void apply_row_swap(MatrixState& ms, int r1, int r2, const array<Bits, N>& new_cols, int delta) {\n        swap(ms.a[r1], ms.a[r2]);\n        swap(ms.row_bits[r1], ms.row_bits[r2]);\n\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int c = 0; c < N; ++c) {\n            olds.push_back(ms.col_bits[c]);\n            news.push_back(new_cols[c]);\n            ms.col_bits[c] = new_cols[c];\n        }\n        apply_many(ms, olds, news);\n        ms.score += delta;\n    }\n\n    int eval_col_rotate(const MatrixState& ms, int c, int sh, array<Bits, N>& new_rows) const {\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                seq[j] = (j == c ? ms.a[(r + sh) % N][c] : ms.a[r][j]);\n            }\n            new_rows[r] = compute_bits_seq(seq);\n            olds.push_back(ms.row_bits[r]);\n            news.push_back(new_rows[r]);\n        }\n        return delta_many(ms, olds, news);\n    }\n\n    void apply_col_rotate(MatrixState& ms, int c, int sh, const array<Bits, N>& new_rows, int delta) {\n        array<uint8_t, N> old{};\n        for (int r = 0; r < N; ++r) old[r] = ms.a[r][c];\n        for (int r = 0; r < N; ++r) ms.a[r][c] = old[(r + sh) % N];\n\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int r = 0; r < N; ++r) {\n            olds.push_back(ms.row_bits[r]);\n            news.push_back(new_rows[r]);\n            ms.row_bits[r] = new_rows[r];\n        }\n        apply_many(ms, olds, news);\n        ms.score += delta;\n        // col_bits[c] unchanged by cyclic rotation\n    }\n\n    int eval_col_swap(const MatrixState& ms, int c1, int c2, array<Bits, N>& new_rows) const {\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                if (j == c1) seq[j] = ms.a[r][c2];\n                else if (j == c2) seq[j] = ms.a[r][c1];\n                else seq[j] = ms.a[r][j];\n            }\n            new_rows[r] = compute_bits_seq(seq);\n            olds.push_back(ms.row_bits[r]);\n            news.push_back(new_rows[r]);\n        }\n        return delta_many(ms, olds, news);\n    }\n\n    void apply_col_swap(MatrixState& ms, int c1, int c2, const array<Bits, N>& new_rows, int delta) {\n        for (int r = 0; r < N; ++r) swap(ms.a[r][c1], ms.a[r][c2]);\n        swap(ms.col_bits[c1], ms.col_bits[c2]);\n\n        vector<Bits> olds, news;\n        olds.reserve(N);\n        news.reserve(N);\n        for (int r = 0; r < N; ++r) {\n            olds.push_back(ms.row_bits[r]);\n            news.push_back(new_rows[r]);\n            ms.row_bits[r] = new_rows[r];\n        }\n        apply_many(ms, olds, news);\n        ms.score += delta;\n    }\n\n    void symmetry_hill_climb(MatrixState& ms) {\n        // Exploit torus symmetries:\n        // - row rotation keeps horizontal coverage\n        // - col rotation keeps vertical coverage\n        // - row/col swap likewise preserve one orientation\n        while (timer.elapsed() < 1.85) {\n            int best_delta = 0;\n            int best_type = -1;\n            int best_a = -1, best_b = -1;\n\n            array<Bits, N> best_cols{}, best_rows{};\n\n            // Row rotations\n            for (int r = 0; r < N; ++r) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_rotate(ms, r, sh, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 0;\n                        best_a = r;\n                        best_b = sh;\n                        best_cols = new_cols;\n                    }\n                }\n            }\n\n            // Row swaps\n            for (int r1 = 0; r1 < N; ++r1) {\n                for (int r2 = r1 + 1; r2 < N; ++r2) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_swap(ms, r1, r2, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 1;\n                        best_a = r1;\n                        best_b = r2;\n                        best_cols = new_cols;\n                    }\n                }\n            }\n\n            // Column rotations\n            for (int c = 0; c < N; ++c) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_rotate(ms, c, sh, new_rows);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 2;\n                        best_a = c;\n                        best_b = sh;\n                        best_rows = new_rows;\n                    }\n                }\n            }\n\n            // Column swaps\n            for (int c1 = 0; c1 < N; ++c1) {\n                for (int c2 = c1 + 1; c2 < N; ++c2) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_swap(ms, c1, c2, new_rows);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 3;\n                        best_a = c1;\n                        best_b = c2;\n                        best_rows = new_rows;\n                    }\n                }\n            }\n\n            if (best_delta <= 0) break;\n\n            if (best_type == 0) apply_row_rotate(ms, best_a, best_b, best_cols, best_delta);\n            else if (best_type == 1) apply_row_swap(ms, best_a, best_b, best_cols, best_delta);\n            else if (best_type == 2) apply_col_rotate(ms, best_a, best_b, best_rows, best_delta);\n            else if (best_type == 3) apply_col_swap(ms, best_a, best_b, best_rows, best_delta);\n        }\n    }\n\n    void cell_local_search(MatrixState& ms) {\n        uniform_real_distribution<double> urd(0.0, 1.0);\n        auto bestA = ms.a;\n        int bestScore = ms.score;\n\n        const double TL = 2.95;\n        while (timer.elapsed() < TL) {\n            double prog = timer.elapsed() / TL;\n            double T = 1.5 * pow(0.02 / 1.5, prog);\n\n            int mode = (int)(rng() % 10);\n            if (mode < 8) {\n                // mostly cell changes\n                int r = (int)(rng() % N);\n                int c = (int)(rng() % N);\n                uint8_t oldch = ms.a[r][c];\n\n                Bits oldR = ms.row_bits[r];\n                Bits oldC = ms.col_bits[c];\n\n                int best_delta = -1e9;\n                uint8_t best_ch = oldch;\n                Bits bestR = oldR, bestC = oldC;\n\n                // greedy best-of-8\n                for (uint8_t ch = 0; ch < 8; ++ch) {\n                    if (ch == oldch) continue;\n                    ms.a[r][c] = ch;\n                    Bits newR = compute_row_bits(ms, r);\n                    Bits newC = compute_col_bits(ms, c);\n                    int delta = calc_delta_two(ms, oldR, newR, oldC, newC);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_ch = ch;\n                        bestR = newR;\n                        bestC = newC;\n                    }\n                }\n\n                bool accept = false;\n                if (best_delta >= 0) accept = true;\n                else {\n                    if (urd(rng) < exp((double)best_delta / T)) accept = true;\n                }\n\n                if (accept && best_ch != oldch) {\n                    ms.a[r][c] = best_ch;\n                    apply_two(ms, oldR, bestR, oldC, bestC);\n                    ms.row_bits[r] = bestR;\n                    ms.col_bits[c] = bestC;\n                    ms.score += best_delta;\n                    if (ms.score > bestScore) {\n                        bestScore = ms.score;\n                        bestA = ms.a;\n                    }\n                } else {\n                    ms.a[r][c] = oldch;\n                }\n            } else if (mode == 8) {\n                // occasional random row rotation\n                int r = (int)(rng() % N);\n                int sh = (int)(rng() % (N - 1)) + 1;\n                array<Bits, N> new_cols;\n                int delta = eval_row_rotate(ms, r, sh, new_cols);\n                if (delta >= 0 || urd(rng) < exp((double)delta / T)) {\n                    apply_row_rotate(ms, r, sh, new_cols, delta);\n                    if (ms.score > bestScore) {\n                        bestScore = ms.score;\n                        bestA = ms.a;\n                    }\n                }\n            } else {\n                // occasional random column rotation\n                int c = (int)(rng() % N);\n                int sh = (int)(rng() % (N - 1)) + 1;\n                array<Bits, N> new_rows;\n                int delta = eval_col_rotate(ms, c, sh, new_rows);\n                if (delta >= 0 || urd(rng) < exp((double)delta / T)) {\n                    apply_col_rotate(ms, c, sh, new_rows, delta);\n                    if (ms.score > bestScore) {\n                        bestScore = ms.score;\n                        bestA = ms.a;\n                    }\n                }\n            }\n        }\n\n        ms.a = bestA;\n    }\n\n    vector<string> solve() {\n        int n;\n        cin >> n >> M;\n\n        array<unordered_map<uint64_t, int>, MAXL + 1> cnt_of;\n        for (int len = MINL; len <= MAXL; ++len) cnt_of[len].reserve(M * 2);\n\n        for (int i = 0; i < M; ++i) {\n            string s;\n            cin >> s;\n            cnt_of[(int)s.size()][encode_string(s)]++;\n        }\n\n        pats.clear();\n        for (int len = MINL; len <= MAXL; ++len) {\n            id_of[len].clear();\n            id_of[len].reserve(cnt_of[len].size() * 2 + 1);\n            for (auto &kv : cnt_of[len]) {\n                Pattern p;\n                p.len = len;\n                p.code = kv.first;\n                p.weight = kv.second;\n                p.s = decode_string(kv.first, len);\n                int id = (int)pats.size();\n                pats.push_back(std::move(p));\n                id_of[len][kv.first] = id;\n            }\n        }\n\n        K = (int)pats.size();\n        orig_weight.assign(K, 0);\n        for (int i = 0; i < K; ++i) orig_weight[i] = pats[i].weight;\n\n        build_ac();\n\n        auto rows = build_initial_rows();\n\n        MatrixState ms;\n        init_matrix_state(ms, rows);\n\n        // symmetry-only hill climbing first\n        if (ms.score < M) symmetry_hill_climb(ms);\n\n        // then cell-based local search on the real full objective\n        if (ms.score < M && timer.elapsed() < 2.95) cell_local_search(ms);\n\n        vector<string> ans(N, string(N, 'A'));\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ans[r][c] = v2ch(ms.a[r][c]);\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    auto ans = solver.solve();\n    for (auto &s : ans) cout << s << '\\n';\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\n\nstruct Dinic {\n    struct Edge {\n        int to, rev;\n        ll cap;\n    };\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic() {}\n    Dinic(int n) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, ll 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\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();\n            q.pop();\n            for (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\n    ll dfs(int v, int t, ll 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[v] >= level[e.to]) continue;\n            ll d = dfs(e.to, t, min(f, e.cap));\n            if (d <= 0) continue;\n            e.cap -= d;\n            g[e.to][e.rev].cap += d;\n            return d;\n        }\n        return 0;\n    }\n\n    ll maxflow(int s, int t) {\n        ll flow = 0;\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n            while (true) {\n                ll f = dfs(s, t, INF64);\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n\n    vector<char> reachable_from(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();\n            q.pop();\n            for (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\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    cin >> N >> si >> sj;\n    vector<string> c(N);\n    for (int i = 0; i < N; i++) cin >> c[i];\n\n    // Enumerate road cells\n    vector<vector<int>> cellId(N, vector<int>(N, -1));\n    vector<int> rr, cc, enterCost;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (c[i][j] != '#') {\n                cellId[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                enterCost.push_back(c[i][j] - '0');\n            }\n        }\n    }\n    int M = (int)rr.size();\n    int startCell = cellId[si][sj];\n\n    // Adjacency of road cells\n    vector<vector<int>> nbr(M);\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (0 <= ni && ni < N && 0 <= nj && nj < N && cellId[ni][nj] != -1) {\n                nbr[id].push_back(cellId[ni][nj]);\n            }\n        }\n    }\n\n    auto dijkstra = [&](int src, bool reverse, bool needPrev) {\n        vector<ll> dist(M, INF64);\n        vector<int> prev(needPrev ? M : 0, -1);\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n        while (!pq.empty()) {\n            auto [cd, u] = pq.top();\n            pq.pop();\n            if (cd != dist[u]) continue;\n            for (int v : nbr[u]) {\n                ll w = reverse ? enterCost[u] : enterCost[v];\n                ll nd = cd + w;\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (needPrev) prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n        return pair<vector<ll>, vector<int>>(move(dist), move(prev));\n    };\n\n    auto [distFromStart, _p0] = dijkstra(startCell, false, false);\n    auto [distToStart, _p1] = dijkstra(startCell, true, false);\n\n    // Segment decomposition\n    vector<vector<int>> hSeg(N, vector<int>(N, -1));\n    vector<vector<int>> vSeg(N, vector<int>(N, -1));\n    int Hcnt = 0, Vcnt = 0;\n\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (c[i][j] == '#') {\n                j++;\n                continue;\n            }\n            int k = j;\n            while (k < N && c[i][k] != '#') {\n                hSeg[i][k] = Hcnt;\n                k++;\n            }\n            Hcnt++;\n            j = k;\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (c[i][j] == '#') {\n                i++;\n                continue;\n            }\n            int k = i;\n            while (k < N && c[k][j] != '#') {\n                vSeg[k][j] = Vcnt;\n                k++;\n            }\n            Vcnt++;\n            i = k;\n        }\n    }\n\n    vector<int> cellH(M), cellV(M);\n    vector<vector<int>> cellsOfH(Hcnt), cellsOfV(Vcnt);\n    vector<vector<int>> adjV(Hcnt);\n    vector<vector<int>> adjCellH(Hcnt);\n\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        int h = hSeg[i][j];\n        int v = vSeg[i][j];\n        cellH[id] = h;\n        cellV[id] = v;\n        cellsOfH[h].push_back(id);\n        cellsOfV[v].push_back(id);\n        adjV[h].push_back(v);\n        adjCellH[h].push_back(id);\n    }\n\n    int startH = cellH[startCell];\n    int startV = cellV[startCell];\n\n    // Weight of a segment = cheapest roundtrip estimate to touch it\n    vector<ll> wH(Hcnt, INF64), wV(Vcnt, INF64);\n    for (int id = 0; id < M; id++) {\n        ll w = distFromStart[id] + distToStart[id];\n        wH[cellH[id]] = min(wH[cellH[id]], w);\n        wV[cellV[id]] = min(wV[cellV[id]], w);\n    }\n    // Already visible at time 0\n    wH[startH] = 0;\n    wV[startV] = 0;\n\n    // Weighted minimum vertex cover on bipartite graph via min-cut\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    Dinic mf(Hcnt + Vcnt + 2);\n    ll sumW = 0;\n    for (int h = 0; h < Hcnt; h++) {\n        mf.add_edge(S, h, wH[h]);\n        sumW += wH[h];\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        mf.add_edge(Hcnt + v, T, wV[v]);\n        sumW += wV[v];\n    }\n    ll BIG = sumW + 1;\n    if (BIG < (ll)1e15) BIG = (ll)1e15;\n    for (int h = 0; h < Hcnt; h++) {\n        for (int v : adjV[h]) {\n            mf.add_edge(h, Hcnt + v, BIG);\n        }\n    }\n    mf.maxflow(S, T);\n    vector<char> reach = mf.reachable_from(S);\n\n    vector<char> selH(Hcnt, 0), selV(Vcnt, 0);\n    for (int h = 0; h < Hcnt; h++) selH[h] = !reach[h];\n    for (int v = 0; v < Vcnt; v++) selV[v] = reach[Hcnt + v];\n\n    // start cell already activates its own segments\n    vector<char> needH = selH, needV = selV;\n    needH[startH] = 0;\n    needV[startV] = 0;\n\n    auto cellRoundTrip = [&](int id) -> ll {\n        return distFromStart[id] + distToStart[id];\n    };\n\n    // Greedy watch-cell selection:\n    // choose cells that cover remaining selected segments cheaply,\n    // preferring cells that cover both an H and a V at once.\n    vector<char> chosenCell(M, 0);\n    int remainH = 0, remainV = 0;\n    for (int h = 0; h < Hcnt; h++) if (needH[h]) remainH++;\n    for (int v = 0; v < Vcnt; v++) if (needV[v]) remainV++;\n\n    while (remainH > 0 || remainV > 0) {\n        int bestCell = -1;\n        ll bestCost = INF64;\n        int bestBenefit = -1;\n\n        for (int id = 0; id < M; id++) {\n            int h = cellH[id], v = cellV[id];\n            int benefit = (needH[h] ? 1 : 0) + (needV[v] ? 1 : 0);\n            if (benefit == 0) continue;\n            ll cost = cellRoundTrip(id);\n\n            if (bestCell == -1) {\n                bestCell = id;\n                bestCost = cost;\n                bestBenefit = benefit;\n            } else {\n                // compare cost/benefit without floating point\n                __int128 lhs = (__int128)cost * bestBenefit;\n                __int128 rhs = (__int128)bestCost * benefit;\n                bool better = false;\n                if (lhs != rhs) better = lhs < rhs;\n                else if (benefit != bestBenefit) better = benefit > bestBenefit;\n                else if (cost != bestCost) better = cost < bestCost;\n                else if (rr[id] != rr[bestCell]) better = rr[id] < rr[bestCell];\n                else better = cc[id] < cc[bestCell];\n                if (better) {\n                    bestCell = id;\n                    bestCost = cost;\n                    bestBenefit = benefit;\n                }\n            }\n        }\n\n        if (bestCell == -1) break; // should not happen\n\n        chosenCell[bestCell] = 1;\n        int h = cellH[bestCell], v = cellV[bestCell];\n        if (needH[h]) {\n            needH[h] = 0;\n            remainH--;\n        }\n        if (needV[v]) {\n            needV[v] = 0;\n            remainV--;\n        }\n    }\n\n    // Remove redundant chosen cells while keeping all selected segments activated\n    vector<int> chosenList;\n    for (int id = 0; id < M; id++) if (chosenCell[id]) chosenList.push_back(id);\n\n    vector<int> cntSelH(Hcnt, 0), cntSelV(Vcnt, 0);\n    if (selH[startH]) cntSelH[startH]++;\n    if (selV[startV]) cntSelV[startV]++;\n    for (int id : chosenList) {\n        if (selH[cellH[id]]) cntSelH[cellH[id]]++;\n        if (selV[cellV[id]]) cntSelV[cellV[id]]++;\n    }\n\n    sort(chosenList.begin(), chosenList.end(), [&](int a, int b) {\n        ll wa = cellRoundTrip(a), wb = cellRoundTrip(b);\n        if (wa != wb) return wa > wb; // remove expensive first\n        if (rr[a] != rr[b]) return rr[a] < rr[b];\n        return cc[a] < cc[b];\n    });\n\n    for (int id : chosenList) {\n        if (!chosenCell[id]) continue;\n        int h = cellH[id], v = cellV[id];\n        bool ok = true;\n        if (selH[h] && cntSelH[h] <= 1) ok = false;\n        if (selV[v] && cntSelV[v] <= 1) ok = false;\n        if (ok) {\n            chosenCell[id] = 0;\n            if (selH[h]) cntSelH[h]--;\n            if (selV[v]) cntSelV[v]--;\n        }\n    }\n\n    // Waypoints = start + selected watch cells\n    vector<int> relCells;\n    relCells.push_back(startCell);\n    for (int id = 0; id < M; id++) {\n        if (chosenCell[id] && id != startCell) relCells.push_back(id);\n    }\n    int R = (int)relCells.size();\n\n    // Distances / predecessors from each waypoint\n    vector<vector<ll>> distMat(R, vector<ll>(R, INF64));\n    vector<vector<int>> prevs(R, vector<int>(M, -1));\n    for (int s = 0; s < R; s++) {\n        auto [dist, prev] = dijkstra(relCells[s], false, true);\n        prevs[s] = move(prev);\n        for (int t = 0; t < R; t++) distMat[s][t] = dist[relCells[t]];\n    }\n\n    auto cycleCost = [&](const vector<int>& cyc) -> ll {\n        int sz = (int)cyc.size();\n        ll ret = 0;\n        for (int i = 0; i < sz; i++) {\n            ret += distMat[cyc[i]][cyc[(i + 1) % sz]];\n        }\n        return ret;\n    };\n\n    // Initial route: cheapest insertion\n    vector<int> cycle;\n    if (R == 1) {\n        cycle = {0};\n    } else {\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestInit = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll v = distMat[0][i] + distMat[i][0];\n            if (v < bestInit) {\n                bestInit = v;\n                first = i;\n            }\n        }\n        cycle = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            ll bestDelta = INF64;\n            int bestNode = -1, bestPos = -1;\n            int sz = (int)cycle.size();\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                for (int pos = 0; pos < sz; pos++) {\n                    int a = cycle[pos];\n                    int b = cycle[(pos + 1) % sz];\n                    ll delta = distMat[a][x] + distMat[x][b] - distMat[a][b];\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestNode = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            used[bestNode] = 1;\n            cycle.insert(cycle.begin() + bestPos + 1, bestNode);\n        }\n\n        // Local search: relocate + swap\n        for (int phase = 0; phase < 3; phase++) {\n            bool improved = true;\n            while (improved) {\n                improved = false;\n                int sz = (int)cycle.size();\n\n                // Relocate\n                for (int i = 1; i < sz && !improved; i++) {\n                    int x = cycle[i];\n                    int a = cycle[(i - 1 + sz) % sz];\n                    int b = cycle[(i + 1) % sz];\n                    ll rem = distMat[a][b] - distMat[a][x] - distMat[x][b];\n\n                    for (int j = 0; j < sz && !improved; j++) {\n                        if (j == i || j == (i - 1 + sz) % sz) continue;\n                        int c1 = cycle[j];\n                        int d1 = cycle[(j + 1) % sz];\n                        ll add = distMat[c1][x] + distMat[x][d1] - distMat[c1][d1];\n                        if (rem + add < 0) {\n                            cycle.erase(cycle.begin() + i);\n                            if (j > i) j--;\n                            cycle.insert(cycle.begin() + j + 1, x);\n                            improved = true;\n                        }\n                    }\n                }\n                if (improved) continue;\n\n                // Swap\n                sz = (int)cycle.size();\n                for (int i = 1; i < sz && !improved; i++) {\n                    for (int j = i + 1; j < sz && !improved; j++) {\n                        vector<int> nc = cycle;\n                        swap(nc[i], nc[j]);\n                        if (cycleCost(nc) < cycleCost(cycle)) {\n                            cycle.swap(nc);\n                            improved = true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Precompute path-segment coverage for every directed arc waypoint s -> t\n    int RR = R;\n    vector<vector<int>> arcHs(RR * RR), arcVs(RR * RR);\n    vector<int> seenH(Hcnt, -1), seenV(Vcnt, -1);\n    int stamp = 0;\n\n    auto build_arc_coverage = [&](int s, int t) {\n        int idx = s * RR + t;\n        stamp++;\n\n        vector<int> pathCells;\n        int srcCell = relCells[s];\n        int dstCell = relCells[t];\n\n        pathCells.push_back(srcCell);\n        if (srcCell != dstCell) {\n            vector<int> rev;\n            int cur = dstCell;\n            while (cur != srcCell) {\n                int p = prevs[s][cur];\n                if (p == -1) break; // connected component should prevent this\n                rev.push_back(cur);\n                cur = p;\n            }\n            reverse(rev.begin(), rev.end());\n            for (int x : rev) pathCells.push_back(x);\n        }\n\n        auto &hs = arcHs[idx];\n        auto &vs = arcVs[idx];\n        hs.clear();\n        vs.clear();\n\n        for (int cell : pathCells) {\n            int h = cellH[cell], v = cellV[cell];\n            if (seenH[h] != stamp) {\n                seenH[h] = stamp;\n                hs.push_back(h);\n            }\n            if (seenV[v] != stamp) {\n                seenV[v] = stamp;\n                vs.push_back(v);\n            }\n        }\n    };\n\n    for (int s = 0; s < RR; s++) {\n        for (int t = 0; t < RR; t++) {\n            build_arc_coverage(s, t);\n        }\n    }\n\n    auto add_arc_cov = [&](vector<int>& cntH2, vector<int>& cntV2, int a, int b, int delta) {\n        int idx = a * RR + b;\n        for (int h : arcHs[idx]) cntH2[h] += delta;\n        for (int v : arcVs[idx]) cntV2[v] += delta;\n    };\n\n    auto full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2) -> bool {\n        for (int id = 0; id < M; id++) {\n            if (cntH2[cellH[id]] == 0 && cntV2[cellV[id]] == 0) return false;\n        }\n        return true;\n    };\n\n    // Coverage-preserving waypoint deletion using actual route paths\n    vector<int> covH(Hcnt, 0), covV(Vcnt, 0);\n    {\n        int sz = (int)cycle.size();\n        for (int i = 0; i < sz; i++) {\n            int a = cycle[i];\n            int b = cycle[(i + 1) % sz];\n            add_arc_cov(covH, covV, a, b, +1);\n        }\n    }\n\n    while ((int)cycle.size() > 1) {\n        int sz = (int)cycle.size();\n        int bestPos = -1;\n        ll bestDelta = 0; // want most negative\n\n        for (int pos = 1; pos < sz; pos++) { // never delete start at position 0\n            int a = cycle[(pos - 1 + sz) % sz];\n            int b = cycle[pos];\n            int c2 = cycle[(pos + 1) % sz];\n            ll delta = distMat[a][c2] - distMat[a][b] - distMat[b][c2];\n\n            add_arc_cov(covH, covV, a, b, -1);\n            add_arc_cov(covH, covV, b, c2, -1);\n            add_arc_cov(covH, covV, a, c2, +1);\n\n            bool ok = full_covered(covH, covV);\n\n            add_arc_cov(covH, covV, a, c2, -1);\n            add_arc_cov(covH, covV, a, b, +1);\n            add_arc_cov(covH, covV, b, c2, +1);\n\n            if (ok && delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = pos;\n            }\n        }\n\n        if (bestPos == -1) break;\n\n        int a = cycle[(bestPos - 1 + sz) % sz];\n        int b = cycle[bestPos];\n        int c2 = cycle[(bestPos + 1) % sz];\n\n        add_arc_cov(covH, covV, a, b, -1);\n        add_arc_cov(covH, covV, b, c2, -1);\n        add_arc_cov(covH, covV, a, c2, +1);\n\n        cycle.erase(cycle.begin() + bestPos);\n    }\n\n    auto dirChar = [&](int a, int b) -> char {\n        int ra = rr[a], ca = cc[a];\n        int rb = rr[b], cb = cc[b];\n        if (rb == ra - 1 && cb == ca) return 'U';\n        if (rb == ra + 1 && cb == ca) return 'D';\n        if (rb == ra && cb == ca - 1) return 'L';\n        return 'R';\n    };\n\n    string ans;\n    int sz = (int)cycle.size();\n    for (int idx = 0; idx < sz; idx++) {\n        int s = cycle[idx];\n        int t = cycle[(idx + 1) % sz];\n        int sCell = relCells[s];\n        int tCell = relCells[t];\n        if (sCell == tCell) continue;\n\n        vector<int> rev;\n        int cur = tCell;\n        while (cur != sCell) {\n            int p = prevs[s][cur];\n            if (p == -1) break;\n            rev.push_back(cur);\n            cur = p;\n        }\n        reverse(rev.begin(), rev.end());\n\n        int curCell = sCell;\n        for (int nxt : rev) {\n            ans.push_back(dirChar(curCell, nxt));\n            curCell = nxt;\n        }\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 1000;\n\nstruct Observation {\n    int task;\n    int t;\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>> children(N), parents(N);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        children[u].push_back(v);\n        parents[v].push_back(u);\n    }\n\n    // ----------------------------\n    // Precompute task statistics\n    // ----------------------------\n    vector<int> indeg(N), rem_pre(N);\n    vector<int> sumd(N, 0), outdeg(N, 0);\n    vector<int> maxd(K, 0);\n    vector<double> avgd(K, 0.0);\n\n    for (int i = 0; i < N; ++i) {\n        indeg[i] = (int)parents[i].size();\n        rem_pre[i] = indeg[i];\n        outdeg[i] = (int)children[i].size();\n        for (int k = 0; k < K; ++k) {\n            sumd[i] += d[i][k];\n            maxd[k] = max(maxd[k], d[i][k]);\n            avgd[k] += d[i][k];\n        }\n    }\n    for (int k = 0; k < K; ++k) avgd[k] /= N;\n\n    // Initial skill guess: member skill norm is larger than task norm on average.\n    vector<int> init_skill(K);\n    for (int k = 0; k < K; ++k) {\n        int v = (int)llround(avgd[k] * 1.6);\n        v = max(0, min(v, maxd[k]));\n        init_skill[k] = v;\n    }\n\n    // Descendant count by bitset DP\n    vector<bitset<MAXN>> reach(N);\n    vector<int> desc_cnt(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        for (int ch : children[i]) {\n            reach[i] |= reach[ch];\n            reach[i].set(ch);\n        }\n        desc_cnt[i] = (int)reach[i].count();\n    }\n\n    // Weighted bottom level\n    vector<long long> bottom(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        long long best_child = 0;\n        for (int ch : children[i]) best_child = max(best_child, bottom[ch]);\n        long long node_w = sumd[i] + 5;\n        bottom[i] = node_w + best_child;\n    }\n\n    vector<long long> priority(N, 0);\n    for (int i = 0; i < N; ++i) {\n        // Tuned static priority:\n        // critical path weight + descendant count + direct unlock count + task size\n        priority[i] = bottom[i] * 30LL + desc_cnt[i] * 5LL + outdeg[i] * 20LL + sumd[i];\n    }\n\n    auto calc_w_with_skill = [&](int task, const vector<int>& skill) -> int {\n        int w = 0;\n        for (int k = 0; k < K; ++k) {\n            if (d[task][k] > skill[k]) w += d[task][k] - skill[k];\n        }\n        return w;\n    };\n\n    vector<int> default_w(N), default_t(N);\n    for (int i = 0; i < N; ++i) {\n        default_w[i] = calc_w_with_skill(i, init_skill);\n        default_t[i] = max(1, default_w[i]);\n    }\n\n    // ----------------------------\n    // Online state\n    // ----------------------------\n    // task_status: -1 = not started, 0 = in progress, 1 = completed\n    vector<int> task_status(N, -1);\n\n    // member current task\n    vector<int> current_task(M, -1);\n    vector<int> start_day(M, -1);\n\n    // estimated skills\n    vector<vector<int>> skill_hat(M, init_skill);\n    vector<vector<Observation>> obs(M);\n\n    auto loss_interval = [&](int w, int t) -> double {\n        int L, U;\n        if (t <= 1) {\n            L = 0;\n            U = 3;\n        } else {\n            L = max(0, t - 3);\n            U = t + 3;\n        }\n        double dist = 0.0;\n        if (w < L) dist = (double)(L - w);\n        else if (w > U) dist = (double)(w - U);\n        else dist = 0.0;\n\n        double weight = (t <= 1 ? 1.0 : 1.0 + 0.05 * min(t, 20));\n        return dist * dist * weight;\n    };\n\n    auto optimize_member = [&](int j) {\n        int T = (int)obs[j].size();\n        if (T == 0) return;\n\n        vector<int>& s = skill_hat[j];\n        vector<int> curW(T);\n        for (int idx = 0; idx < T; ++idx) {\n            curW[idx] = calc_w_with_skill(obs[j][idx].task, s);\n        }\n\n        int max_iter = 3;\n        for (int it = 0; it < max_iter; ++it) {\n            bool changed = false;\n\n            for (int k = 0; k < K; ++k) {\n                int prev = s[k];\n\n                vector<int> base(T);\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    base[idx] = curW[idx] - max(0, d[task][k] - prev);\n                }\n\n                double best_obj = 1e100;\n                int best_x = prev;\n                int best_tie1 = 0;\n                int best_tie2 = abs(prev - init_skill[k]);\n\n                for (int x = 0; x <= maxd[k]; ++x) {\n                    double obj = 0.0;\n                    for (int idx = 0; idx < T; ++idx) {\n                        int task = obs[j][idx].task;\n                        int w = base[idx] + max(0, d[task][k] - x);\n                        obj += loss_interval(w, obs[j][idx].t);\n                    }\n\n                    int tie1 = abs(x - prev);\n                    int tie2 = abs(x - init_skill[k]);\n                    if (obj + 1e-9 < best_obj ||\n                        (abs(obj - best_obj) <= 1e-9 &&\n                         (tie1 < best_tie1 || (tie1 == best_tie1 && tie2 < best_tie2)))) {\n                        best_obj = obj;\n                        best_x = x;\n                        best_tie1 = tie1;\n                        best_tie2 = tie2;\n                    }\n                }\n\n                if (best_x != prev) changed = true;\n                s[k] = best_x;\n\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    curW[idx] = base[idx] + max(0, d[task][k] - best_x);\n                }\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto estimate_time = [&](int member, int task) -> double {\n        // Blend default estimate and learned estimate based on observation count.\n        double trust = (double)obs[member].size() / ((double)obs[member].size() + 5.0);\n        int learned_w = calc_w_with_skill(task, skill_hat[member]);\n        double p = (1.0 - trust) * default_w[task] + trust * learned_w;\n        return max(1.0, p);\n    };\n\n    auto get_ready_tasks = [&]() -> vector<int> {\n        vector<int> ready;\n        ready.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (task_status[i] == -1 && rem_pre[i] == 0) ready.push_back(i);\n        }\n        return ready;\n    };\n\n    auto select_candidates = [&](const vector<int>& ready, int free_cnt) -> vector<int> {\n        if ((int)ready.size() <= max(60, free_cnt * 5)) return ready;\n\n        int take_priority = max(20, free_cnt * 3);\n        int take_easy = max(10, free_cnt * 2);\n\n        vector<int> by_pri = ready;\n        sort(by_pri.begin(), by_pri.end(), [&](int a, int b) {\n            if (priority[a] != priority[b]) return priority[a] > priority[b];\n            return a < b;\n        });\n\n        vector<int> by_easy = ready;\n        sort(by_easy.begin(), by_easy.end(), [&](int a, int b) {\n            if (default_t[a] != default_t[b]) return default_t[a] < default_t[b];\n            if (priority[a] != priority[b]) return priority[a] > priority[b];\n            return a < b;\n        });\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(take_priority + take_easy);\n\n        for (int i = 0; i < (int)by_pri.size() && (int)cand.size() < take_priority; ++i) {\n            int t = by_pri[i];\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_easy.size() && i < take_easy; ++i) {\n            int t = by_easy[i];\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        // Ensure enough candidates\n        for (int t : by_pri) {\n            if ((int)cand.size() >= max(30, free_cnt * 5)) break;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        return cand;\n    };\n\n    auto decide_assignments = [&]() -> vector<pair<int,int>> {\n        vector<int> free_members;\n        for (int j = 0; j < M; ++j) {\n            if (current_task[j] == -1) free_members.push_back(j);\n        }\n\n        vector<int> ready = get_ready_tasks();\n        if (free_members.empty() || ready.empty()) return {};\n\n        vector<int> cand = select_candidates(ready, (int)free_members.size());\n        int F = (int)free_members.size();\n        int C = (int)cand.size();\n\n        const long long TIME_PENALTY = 800;  // tuned balance\n\n        vector<vector<long long>> score(F, vector<long long>(C));\n        for (int fi = 0; fi < F; ++fi) {\n            int mem = free_members[fi];\n            for (int ci = 0; ci < C; ++ci) {\n                int task = cand[ci];\n                double et = estimate_time(mem, task);\n                score[fi][ci] = priority[task] - (long long)llround(et * TIME_PENALTY);\n            }\n        }\n\n        vector<char> used_f(F, 0), used_c(C, 0);\n        vector<pair<int,int>> ret;\n        int rounds = min(F, C);\n\n        for (int step = 0; step < rounds; ++step) {\n            long long best_score = LLONG_MIN;\n            int best_f = -1, best_c = -1;\n            for (int fi = 0; fi < F; ++fi) if (!used_f[fi]) {\n                for (int ci = 0; ci < C; ++ci) if (!used_c[ci]) {\n                    if (score[fi][ci] > best_score) {\n                        best_score = score[fi][ci];\n                        best_f = fi;\n                        best_c = ci;\n                    }\n                }\n            }\n            if (best_f == -1) break;\n            used_f[best_f] = 1;\n            used_c[best_c] = 1;\n            ret.emplace_back(free_members[best_f], cand[best_c]);\n        }\n        return ret;\n    };\n\n    // ----------------------------\n    // Interactive loop\n    // ----------------------------\n    int day = 0;\n    while (true) {\n        ++day;\n\n        vector<pair<int,int>> assigns = decide_assignments();\n\n        // Apply assignment to local state before reading today's completion.\n        for (auto [mem, task] : assigns) {\n            task_status[task] = 0;\n            current_task[mem] = task;\n            start_day[mem] = day;\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        int nfin;\n        cin >> nfin;\n        if (!cin) return 0;\n        if (nfin == -1) {\n            return 0;\n        }\n\n        vector<int> finished(nfin);\n        for (int i = 0; i < nfin; ++i) {\n            cin >> finished[i];\n            --finished[i];\n        }\n\n        // Process completions at end of day\n        for (int mem : finished) {\n            int task = current_task[mem];\n            if (task == -1) continue; // safety\n\n            int duration = day - start_day[mem] + 1;\n            obs[mem].push_back({task, duration});\n\n            task_status[task] = 1;\n            current_task[mem] = -1;\n            start_day[mem] = -1;\n\n            for (int ch : children[task]) {\n                --rem_pre[ch];\n            }\n\n            optimize_member(mem);\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 1000;\nstatic constexpr int TOT = 2001; // 0: office, 1..1000: pickup, 1001..2000: delivery\nstatic constexpr double TL = 1.95;\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 XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Insertion {\n    int delta;\n    int g1, g2; // insert pickup after seq[g1], delivery after seq[g2] in original seq\n};\n\nstruct State {\n    vector<int> seq;       // route as node ids\n    vector<char> selected; // 1..1000\n    int cost = 0;\n};\n\nint X[TOT], Y[TOT];\nvector<int> DM;               // flat Manhattan distance matrix\nint baseScore[N + 1];\nvector<int> sorted_ids;       // ids sorted by center-based heuristic score\n\ninline int dist_node(int a, int b) {\n    return DM[a * TOT + b];\n}\ninline int pickup_node(int id) { return id; }\ninline int delivery_node(int id) { return N + id; }\n\nint route_cost(const vector<int>& seq) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)seq.size(); i++) s += dist_node(seq[i], seq[i + 1]);\n    return s;\n}\n\nInsertion find_best_insertion(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    const int m = (int)seq.size();\n\n    Insertion best{INT_MAX, -1, -1};\n\n    for (int g1 = 0; g1 < m - 1; g1++) {\n        int a = seq[g1], b = seq[g1 + 1];\n        int dab = dist_node(a, b);\n\n        // pickup and delivery inserted in the same gap: a-u-v-b\n        int delta_same = dist_node(a, u) + dist_node(u, v) + dist_node(v, b) - dab;\n        if (delta_same < best.delta) {\n            best = {delta_same, g1, g1};\n        }\n\n        // pickup inserted at g1, delivery at later gap g2\n        int delta_pick = dist_node(a, u) + dist_node(u, b) - dab;\n        for (int g2 = g1 + 1; g2 < m - 1; g2++) {\n            int c = seq[g2], d = seq[g2 + 1];\n            int delta = delta_pick + dist_node(c, v) + dist_node(v, d) - dist_node(c, d);\n            if (delta < best.delta) {\n                best = {delta, g1, g2};\n            }\n        }\n    }\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& seq, int id, const Insertion& ins) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() + 2);\n\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == ins.g1) {\n            res.push_back(u);\n            if (ins.g2 == ins.g1) res.push_back(v);\n        }\n        if (i == ins.g2 && ins.g2 > ins.g1) {\n            res.push_back(v);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() - 2);\n    for (int x : seq) {\n        if (x != u && x != v) res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> remove_orders(const vector<int>& seq, const vector<int>& rem_ids) {\n    vector<char> bad(N + 1, 0);\n    for (int id : rem_ids) bad[id] = 1;\n    vector<int> res;\n    res.reserve(seq.size() - 2 * (int)rem_ids.size());\n    for (int x : seq) {\n        if (x == 0) {\n            res.push_back(x);\n        } else {\n            int id = (x <= N ? x : x - N);\n            if (!bad[id]) res.push_back(x);\n        }\n    }\n    return res;\n}\n\nvector<int> get_selected_ids(const vector<char>& selected) {\n    vector<int> ids;\n    ids.reserve(50);\n    for (int id = 1; id <= N; id++) if (selected[id]) ids.push_back(id);\n    return ids;\n}\n\nint pick_rcl_index(int sz, XorShift64& rng) {\n    if (sz <= 1) return 0;\n    int r = rng.next_int(0, 99);\n    if (sz == 2) return (r < 72 ? 0 : 1);\n    if (sz == 3) return (r < 55 ? 0 : (r < 85 ? 1 : 2));\n    if (sz == 4) return (r < 45 ? 0 : (r < 73 ? 1 : (r < 90 ? 2 : 3)));\n    if (sz == 5) return (r < 42 ? 0 : (r < 68 ? 1 : (r < 84 ? 2 : (r < 94 ? 3 : 4))));\n    return (r < 40 ? 0 : (r < 64 ? 1 : (r < 79 ? 2 : (r < 89 ? 3 : (r < 96 ? 4 : 5)))));\n}\n\nstruct Cand {\n    int delta;\n    int id;\n    Insertion ins;\n};\n\nvoid push_top_k(vector<Cand>& top, const Cand& c, int topK) {\n    if ((int)top.size() < topK) {\n        top.push_back(c);\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            return baseScore[a.id] < baseScore[b.id];\n        });\n    } else {\n        const auto& w = top.back();\n        if (c.delta < w.delta || (c.delta == w.delta && baseScore[c.id] < baseScore[w.id])) {\n            top.back() = c;\n            sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                if (a.delta != b.delta) return a.delta < b.delta;\n                return baseScore[a.id] < baseScore[b.id];\n            });\n        }\n    }\n}\n\nvector<Cand> collect_top_insertions(\n    const vector<int>& seq,\n    const vector<char>& selected,\n    int limit_ids,\n    int topK,\n    const Timer* timer = nullptr,\n    double end_time = 1e100\n) {\n    vector<Cand> top;\n    top.reserve(topK);\n\n    int lim = min(limit_ids, (int)sorted_ids.size());\n    for (int i = 0; i < lim; i++) {\n        if (timer && timer->elapsed() >= end_time) break;\n        int id = sorted_ids[i];\n        if (selected[id]) continue;\n        Insertion ins = find_best_insertion(seq, id);\n        push_top_k(top, Cand{ins.delta, id, ins}, topK);\n    }\n\n    // safety fallback\n    if (top.empty()) {\n        for (int id = 1; id <= N; id++) {\n            if (selected[id]) continue;\n            Insertion ins = find_best_insertion(seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n    }\n\n    return top;\n}\n\nState construct_solution(int pool_limit, bool randomized, XorShift64& rng, const Timer& timer, double end_time) {\n    State st;\n    st.seq = {0, 0};\n    st.selected.assign(N + 1, 0);\n    st.cost = 0;\n\n    const int topK = randomized ? 6 : 1;\n\n    for (int step = 0; step < 50; step++) {\n        if (timer.elapsed() >= end_time) break;\n        auto top = collect_top_insertions(st.seq, st.selected, pool_limit, topK, &timer, end_time);\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n    }\n\n    // if time cut construction short, fill deterministically\n    while ((int)get_selected_ids(st.selected).size() < 50) {\n        auto top = collect_top_insertions(st.seq, st.selected, N, 1);\n        auto chosen = top[0];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n    }\n\n    return st;\n}\n\nvoid improve_route_relocate(State& st, const Timer& timer, double end_time, int max_passes = 100) {\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_new_cost = st.cost;\n        int best_id = -1;\n        Insertion best_ins;\n        vector<int> best_removed_seq;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int cost_removed = route_cost(seq_removed);\n            Insertion ins = find_best_insertion(seq_removed, id);\n            int new_cost = cost_removed + ins.delta;\n\n            if (new_cost < best_new_cost) {\n                best_new_cost = new_cost;\n                best_id = id;\n                best_ins = ins;\n                best_removed_seq = move(seq_removed);\n            }\n        }\n\n        if (best_id == -1) break;\n        st.seq = apply_insertion(best_removed_seq, best_id, best_ins);\n        st.cost = best_new_cost;\n    }\n}\n\nvoid improve_swap(State& st, const Timer& timer, double end_time) {\n    const int TOP_REMOVE = 12;\n    const int TOP_ADD = 100;\n\n    while (timer.elapsed() < end_time) {\n        struct RemCand {\n            int gain;\n            int id;\n        };\n        vector<RemCand> rems;\n        rems.reserve(50);\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int removed_cost = route_cost(seq_removed);\n            int gain = st.cost - removed_cost;\n            rems.push_back({gain, id});\n        }\n\n        sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.id < b.id;\n        });\n        if ((int)rems.size() > TOP_REMOVE) rems.resize(TOP_REMOVE);\n\n        vector<Cand> adds;\n        adds.reserve(TOP_ADD);\n\n        for (int id = 1; id <= N; id++) {\n            if (timer.elapsed() >= end_time) break;\n            if (st.selected[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(adds, Cand{ins.delta, id, ins}, TOP_ADD);\n        }\n\n        int best_new_cost = st.cost;\n        int best_remove = -1, best_add = -1;\n        Insertion best_ins;\n        vector<int> best_removed_seq;\n\n        for (const auto& rc : rems) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> seq_removed = remove_order(st.seq, rc.id);\n            int cost_removed = route_cost(seq_removed);\n\n            for (const auto& ac : adds) {\n                if (ac.id == rc.id) continue;\n                Insertion ins = find_best_insertion(seq_removed, ac.id);\n                int new_cost = cost_removed + ins.delta;\n                if (new_cost < best_new_cost) {\n                    best_new_cost = new_cost;\n                    best_remove = rc.id;\n                    best_add = ac.id;\n                    best_ins = ins;\n                    best_removed_seq = seq_removed;\n                }\n            }\n        }\n\n        if (best_remove == -1) break;\n\n        st.selected[best_remove] = 0;\n        st.selected[best_add] = 1;\n        st.seq = apply_insertion(best_removed_seq, best_add, best_ins);\n        st.cost = best_new_cost;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.03);\n        improve_route_relocate(st, timer, sub_end, 2);\n    }\n}\n\nbool destroy_and_repair_once(State& st, const Timer& timer, double end_time, XorShift64& rng) {\n    if (timer.elapsed() >= end_time) return false;\n\n    auto selected_ids = get_selected_ids(st.selected);\n\n    struct RemCand {\n        int gain;\n        int id;\n    };\n    vector<RemCand> rems;\n    rems.reserve(50);\n    for (int id : selected_ids) {\n        vector<int> seq_removed = remove_order(st.seq, id);\n        int removed_cost = route_cost(seq_removed);\n        int gain = st.cost - removed_cost;\n        rems.push_back({gain, id});\n    }\n    sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        return a.id < b.id;\n    });\n\n    int elite_rem = min(10, (int)rems.size());\n    bool improved = false;\n\n    for (int trial = 0; trial < 12 && timer.elapsed() < end_time; trial++) {\n        int k = (rng.next_int(0, 99) < 70 ? 2 : 3);\n\n        vector<int> remset;\n        remset.reserve(k);\n\n        while ((int)remset.size() < k) {\n            int id;\n            if (rng.next_int(0, 99) < 80) {\n                id = rems[rng.next_int(0, elite_rem - 1)].id;\n            } else {\n                id = selected_ids[rng.next_int(0, (int)selected_ids.size() - 1)];\n            }\n            bool dup = false;\n            for (int x : remset) if (x == id) dup = true;\n            if (!dup) remset.push_back(id);\n        }\n\n        State tmp;\n        tmp.selected = st.selected;\n        for (int id : remset) tmp.selected[id] = 0;\n        tmp.seq = remove_orders(st.seq, remset);\n        tmp.cost = route_cost(tmp.seq);\n\n        for (int rep = 0; rep < k; rep++) {\n            if (timer.elapsed() >= end_time) break;\n            auto top = collect_top_insertions(tmp.seq, tmp.selected, 700, 6, &timer, end_time);\n            int idx = pick_rcl_index((int)top.size(), rng);\n            auto chosen = top[idx];\n            tmp.seq = apply_insertion(tmp.seq, chosen.id, chosen.ins);\n            tmp.selected[chosen.id] = 1;\n            tmp.cost += chosen.delta;\n        }\n\n        if ((int)get_selected_ids(tmp.selected).size() != 50) continue;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.03);\n        improve_route_relocate(tmp, timer, sub_end, 2);\n\n        if (tmp.cost < st.cost) {\n            st = move(tmp);\n            improved = true;\n            break;\n        }\n    }\n\n    return improved;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    X[0] = 400;\n    Y[0] = 400;\n\n    long long seed = 123456789;\n\n    for (int i = 1; i <= N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        X[i] = a;\n        Y[i] = b;\n        X[N + i] = c;\n        Y[N + i] = d;\n\n        int center_cycle = abs(400 - a) + abs(400 - b) + abs(a - c) + abs(b - d) + abs(c - 400) + abs(d - 400);\n        int center_sum = abs(400 - a) + abs(400 - b) + abs(400 - c) + abs(400 - d);\n        baseScore[i] = center_cycle * 2 + center_sum;\n\n        seed = seed * 1000003 + a * 911 + b * 3571 + c * 1021 + d;\n    }\n\n    DM.assign(TOT * TOT, 0);\n    for (int i = 0; i < TOT; i++) {\n        for (int j = 0; j < TOT; j++) {\n            DM[i * TOT + j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n        }\n    }\n\n    sorted_ids.resize(N);\n    iota(sorted_ids.begin(), sorted_ids.end(), 1);\n    sort(sorted_ids.begin(), sorted_ids.end(), [](int i, int j) {\n        if (baseScore[i] != baseScore[j]) return baseScore[i] < baseScore[j];\n        return i < j;\n    });\n\n    Timer timer;\n    XorShift64 rng((uint64_t)seed);\n\n    State best;\n    bool has_best = false;\n\n    // Multi-start construction with several candidate pool sizes\n    vector<int> pool_limits = {180, 260, 360, 500, 800, 1000};\n    int attempt = 0;\n    while (timer.elapsed() < 0.60) {\n        int pool = pool_limits[attempt % (int)pool_limits.size()];\n        bool randomized = (attempt != 0);\n        double build_end = min(0.62, TL);\n        State st = construct_solution(pool, randomized, rng, timer, build_end);\n\n        double sub_end = min(0.78, TL);\n        improve_route_relocate(st, timer, sub_end, 2);\n\n        if (!has_best || st.cost < best.cost) {\n            best = move(st);\n            has_best = true;\n        }\n        attempt++;\n    }\n\n    if (!has_best) {\n        best = construct_solution(1000, false, rng, timer, TL);\n    }\n\n    // Main search\n    improve_route_relocate(best, timer, 1.10, 100);\n    improve_swap(best, timer, 1.45);\n    improve_route_relocate(best, timer, 1.60, 100);\n\n    while (timer.elapsed() < 1.85) {\n        bool ok = destroy_and_repair_once(best, timer, 1.85, rng);\n        if (!ok) break;\n    }\n\n    improve_swap(best, timer, 1.92);\n    improve_route_relocate(best, timer, TL, 100);\n\n    auto ids = get_selected_ids(best.selected);\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.seq.size();\n    for (int node : best.seq) {\n        cout << ' ' << X[node] << ' ' << Y[node];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int S = 16;          // number of sampled future worlds (even)\nstatic constexpr int INF = 1e9;\n\nstruct Edge {\n    int u, v;\n    int d;\n};\n\ntemplate <int MAXN>\nstruct UnionFind {\n    int p[MAXN], sz[MAXN];\n    int comps;\n\n    void init(int n) {\n        comps = n;\n        for (int i = 0; i < n; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\n\n    int leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    int leader_const(int x) const {\n        while (p[x] != x) x = p[x];\n        return x;\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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        --comps;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 0x123456789abcdefULL) : 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(uint32_t mod) {\n        return (uint32_t)(next_u64() % mod);\n    }\n};\n\npair<int, int> estimate_pair_cost(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int comp_u,\n    int comp_v,\n    const vector<int>& order,\n    const vector<int>& weight,\n    const vector<Edge>& edges\n) {\n    if (K == 1) return {0, 0};\n\n    UnionFind<N> uf_reject, uf_adopt;\n    uf_reject.init(K);\n    uf_adopt.init(K);\n\n    int need_reject = K - 1;\n    int need_adopt = K - 1;\n    if (uf_adopt.merge(comp_u, comp_v)) --need_adopt;\n\n    int cost_reject = 0;\n    int cost_adopt = 0;\n\n    for (int idx : order) {\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (need_reject > 0 && uf_reject.merge(a, b)) {\n            cost_reject += weight[idx];\n            --need_reject;\n        }\n        if (need_adopt > 0 && uf_adopt.merge(a, b)) {\n            cost_adopt += weight[idx];\n            --need_adopt;\n        }\n        if (need_reject == 0 && need_adopt == 0) break;\n    }\n\n    if (need_reject > 0) cost_reject = INF;\n    if (need_adopt > 0) cost_adopt = INF;\n    return {cost_reject, cost_adopt};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int, int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = pos[u].first - pos[v].first;\n        long long dy = pos[u].second - pos[v].second;\n        int d = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Pre-sample future worlds with antithetic sampling.\n    vector<vector<int>> weights(S, vector<int>(M));\n    SplitMix64 rng(0x3141592653589793ULL);\n\n    for (int s = 0; s < S; s += 2) {\n        for (int i = 0; i < M; ++i) {\n            int d = edges[i].d;\n            int span = 2 * d;\n            int t = (int)rng.next_u32((uint32_t)span + 1); // in [0, 2d]\n            weights[s][i] = d + t;\n            weights[s + 1][i] = 3 * d - t;\n        }\n    }\n\n    vector<vector<int>> orders(S, vector<int>(M));\n    for (int s = 0; s < S; ++s) {\n        iota(orders[s].begin(), orders[s].end(), 0);\n        stable_sort(orders[s].begin(), orders[s].end(), [&](int a, int b) {\n            if (weights[s][a] != weights[s][b]) return weights[s][a] < weights[s][b];\n            return a < b;\n        });\n    }\n\n    UnionFind<N> accepted;\n    accepted.init(N);\n\n    int cid[N];\n    int K = N;\n    bool comp_dirty = true;\n\n    auto rebuild_components = [&]() {\n        int mp[N];\n        for (int i = 0; i < N; ++i) mp[i] = -1;\n        K = 0;\n        for (int v = 0; v < N; ++v) {\n            int r = accepted.leader_const(v);\n            if (mp[r] == -1) mp[r] = K++;\n            cid[v] = mp[r];\n        }\n        comp_dirty = false;\n    };\n\n    for (int i = 0; i < M; ++i) {\n        int l;\n        cin >> l;\n\n        int u = edges[i].u;\n        int v = edges[i].v;\n        int ans = 0;\n\n        if (!accepted.same(u, v)) {\n            if (comp_dirty) rebuild_components();\n\n            int cu = cid[u];\n            int cv = cid[v];\n\n            double sum_reject = 0.0;\n            double sum_adopt = 0.0;\n            bool reject_impossible = false;\n\n            for (int s = 0; s < S; ++s) {\n                auto [c_reject, c_adopt] =\n                    estimate_pair_cost(i + 1, K, cid, cu, cv, orders[s], weights[s], edges);\n\n                if (c_reject >= INF) {\n                    reject_impossible = true;\n                    break;\n                }\n                sum_reject += c_reject;\n                sum_adopt += c_adopt;\n            }\n\n            if (reject_impossible) {\n                ans = 1;\n            } else {\n                double reject_value = sum_reject / S;\n                double adopt_value = l + sum_adopt / S;\n                if (adopt_value <= reject_value) ans = 1;\n            }\n        }\n\n        if (ans) {\n            accepted.merge(u, v);\n            comp_dirty = true;\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n    bool operator==(const Pos& o) const { return x == o.x && y == o.y; }\n    bool operator!=(const Pos& o) const { return !(*this == o); }\n};\n\nstatic constexpr int B = 30;\nstatic constexpr int T = 300;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nvector<Pos> pets, humans;\nvector<int> petType;\nbool wallg[31][31];\n\nint chosenCorner = 0;\nint Hrect = 8, Wrect = 8;\n\nvector<Pos> parkTarget;\n\nbool inside(int x, int y) {\n    return 1 <= x && x <= B && 1 <= y && y <= B;\n}\n\nPos addDir(Pos p, char d) {\n    if (d == 'U' || d == 'u') --p.x;\n    else if (d == 'D' || d == 'd') ++p.x;\n    else if (d == 'L' || d == 'l') --p.y;\n    else if (d == 'R' || d == 'r') ++p.y;\n    return p;\n}\n\nPos transformPos(Pos p, int corner) {\n    if (corner == 0) return p;                    // TL\n    if (corner == 1) return {p.x, B + 1 - p.y};  // TR -> TL\n    if (corner == 2) return {B + 1 - p.x, p.y};  // BL -> TL\n    return {B + 1 - p.x, B + 1 - p.y};           // BR -> TL\n}\n\nchar mapDirByCorner(char c, int corner) {\n    bool low = ('a' <= c && c <= 'z');\n    char d = (char)toupper(c);\n    if (corner == 1 || corner == 3) {\n        if (d == 'L') d = 'R';\n        else if (d == 'R') d = 'L';\n    }\n    if (corner == 2 || corner == 3) {\n        if (d == 'U') d = 'D';\n        else if (d == 'D') d = 'U';\n    }\n    if (low) d = (char)tolower(d);\n    return d;\n}\n\nint manhattan(Pos a, Pos b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<Pos> transformedVec(const vector<Pos>& src, int corner) {\n    vector<Pos> res = src;\n    for (auto& p : res) p = transformPos(p, corner);\n    return res;\n}\n\nbool canBuildCell(int tx, int ty, const vector<Pos>& hs, const vector<Pos>& ps) {\n    if (!inside(tx, ty)) return false;\n    if (wallg[tx][ty]) return false;\n    for (auto& h : hs) {\n        if (h.x == tx && h.y == ty) return false;\n    }\n    for (auto& p : ps) {\n        if (p.x == tx && p.y == ty) return false;\n        if (abs(p.x - tx) + abs(p.y - ty) == 1) return false;\n    }\n    return true;\n}\n\nchar bfsNextStep(Pos s, Pos t) {\n    if (s == t) return '.';\n    if (!inside(t.x, t.y) || wallg[t.x][t.y]) return '.';\n\n    static int dist[31][31];\n    for (int i = 1; i <= B; ++i) for (int j = 1; j <= B; ++j) dist[i][j] = -1;\n\n    queue<Pos> q;\n    q.push(t);\n    dist[t.x][t.y] = 0;\n\n    const char dirs[4] = {'U', 'D', 'L', 'R'};\n    while (!q.empty()) {\n        Pos cur = q.front(); q.pop();\n        for (char d : dirs) {\n            Pos nx = addDir(cur, d);\n            if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n            if (dist[nx.x][nx.y] != -1) continue;\n            dist[nx.x][nx.y] = dist[cur.x][cur.y] + 1;\n            q.push(nx);\n        }\n    }\n\n    int best = INF;\n    char ans = '.';\n    const char order[4] = {'U', 'L', 'R', 'D'};\n    for (char d : order) {\n        Pos nx = addDir(s, d);\n        if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n        if (dist[nx.x][nx.y] == -1) continue;\n        if (dist[nx.x][nx.y] < best) {\n            best = dist[nx.x][nx.y];\n            ans = d;\n        }\n    }\n    return ans;\n}\n\nbool allHumansInside() {\n    for (auto& h : humans) {\n        if (h.x > Hrect || h.y > Wrect) return false;\n    }\n    return true;\n}\n\nint countPetsInside() {\n    int c = 0;\n    for (auto& p : pets) if (p.x <= Hrect && p.y <= Wrect) ++c;\n    return c;\n}\n\nbool nonDoorWallsBuilt() {\n    for (int y = 1; y <= Wrect - 1; ++y) {\n        if (!wallg[Hrect + 1][y]) return false;\n    }\n    for (int x = 1; x <= Hrect - 1; ++x) {\n        if (!wallg[x][Wrect + 1]) return false;\n    }\n    return true;\n}\n\nbool closedFully() {\n    return wallg[Hrect + 1][Wrect] && wallg[Hrect][Wrect + 1];\n}\n\nstruct Task {\n    Pos pos;   // human stands here\n    Pos wall;  // build this wall\n    char act;  // build action from pos\n};\n\nvector<Task> getNonDoorTasks() {\n    vector<Task> tasks;\n    for (int y = 1; y <= Wrect - 1; ++y) {\n        if (!wallg[Hrect + 1][y]) tasks.push_back({{Hrect, y}, {Hrect + 1, y}, 'd'});\n    }\n    for (int x = 1; x <= Hrect - 1; ++x) {\n        if (!wallg[x][Wrect + 1]) tasks.push_back({{x, Wrect}, {x, Wrect + 1}, 'r'});\n    }\n    return tasks;\n}\n\nvoid chooseStrategy(const vector<Pos>& initPetsActual, const vector<Pos>& initHumansActual) {\n    double bestValue = -1e100;\n    int bestCorner = 0, bestH = 8, bestW = 8;\n\n    for (int corner = 0; corner < 4; ++corner) {\n        auto tp = transformedVec(initPetsActual, corner);\n        auto th = transformedVec(initHumansActual, corner);\n\n        int occ[31][31] = {};\n        for (auto& p : tp) occ[p.x][p.y]++;\n\n        int pref[31][31] = {};\n        for (int i = 1; i <= B; ++i) {\n            for (int j = 1; j <= B; ++j) {\n                pref[i][j] = occ[i][j] + pref[i-1][j] + pref[i][j-1] - pref[i-1][j-1];\n            }\n        }\n\n        for (int H = 4; H <= 18; ++H) {\n            for (int W = 4; W <= 18; ++W) {\n                int petCnt = pref[H][W];\n                int enterSum = 0, enterMax = 0;\n                for (auto& h : th) {\n                    int d = max(0, h.x - H) + max(0, h.y - W);\n                    enterSum += d;\n                    enterMax = max(enterMax, d);\n                }\n                int buildCells = (H - 1) + (W - 1);\n\n                // Stronger bias toward small pet count; still keep area relevant.\n                double value = 1.0 * H * W * pow(0.50, petCnt)\n                             - 0.55 * enterSum\n                             - 0.20 * enterMax\n                             - 0.20 * buildCells;\n\n                if (petCnt == 0) value += 18.0;\n                else if (petCnt == 1) value += 6.0;\n                else if (petCnt == 2) value += 1.5;\n\n                if (value > bestValue) {\n                    bestValue = value;\n                    bestCorner = corner;\n                    bestH = H;\n                    bestW = W;\n                }\n            }\n        }\n    }\n\n    chosenCorner = bestCorner;\n    Hrect = bestH;\n    Wrect = bestW;\n\n    pets = transformedVec(initPetsActual, chosenCorner);\n    humans = transformedVec(initHumansActual, chosenCorner);\n\n    memset(wallg, 0, sizeof(wallg));\n\n    // Precompute parking positions inside the rectangle.\n    vector<Pos> spots;\n    for (int sum = 2; sum <= Hrect + Wrect; ++sum) {\n        for (int x = 1; x <= Hrect; ++x) {\n            int y = sum - x;\n            if (1 <= y && y <= Wrect) {\n                if (x == Hrect && y == Wrect) continue; // keep corner free-ish\n                spots.push_back({x, y});\n            }\n        }\n    }\n    if (spots.empty()) spots.push_back({1, 1});\n\n    parkTarget.assign(M, {1, 1});\n    vector<int> used(spots.size(), 0);\n    for (int i = 0; i < M; ++i) {\n        int best = -1, bestd = INF;\n        for (int k = 0; k < (int)spots.size(); ++k) if (!used[k]) {\n            int d = manhattan(humans[i], spots[k]);\n            if (d < bestd) {\n                bestd = d;\n                best = k;\n            }\n        }\n        if (best == -1) best = 0;\n        used[best] = 1;\n        parkTarget[i] = spots[best];\n    }\n}\n\nint nearestHumanTo(Pos target, const vector<Pos>& hs) {\n    int id = 0, bd = INF;\n    for (int i = 0; i < (int)hs.size(); ++i) {\n        int d = manhattan(hs[i], target);\n        if (d < bd) {\n            bd = d;\n            id = i;\n        }\n    }\n    return id;\n}\n\nchar moveToward(Pos cur, Pos target) {\n    return bfsNextStep(cur, target);\n}\n\nbool shouldCloseSecondDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 190 && petsInside <= 1) return true;\n    if (turn >= 230 && petsInside <= 2) return true;\n    if (turn >= 270 && petsInside <= 3) return true;\n    if (turn >= 295) return true;\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<Pos> initPetsActual(N);\n    petType.resize(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> initPetsActual[i].x >> initPetsActual[i].y >> petType[i];\n    }\n\n    cin >> M;\n    vector<Pos> initHumansActual(M);\n    for (int i = 0; i < M; ++i) cin >> initHumansActual[i].x >> initHumansActual[i].y;\n\n    chooseStrategy(initPetsActual, initHumansActual);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<Pos> hs0 = humans;\n        vector<Pos> ps0 = pets;\n        vector<char> act(M, '.');\n\n        bool nonDoor = nonDoorWallsBuilt();\n        bool doorDown = wallg[Hrect + 1][Wrect];\n        bool doorRight = wallg[Hrect][Wrect + 1];\n        bool allIn = allHumansInside();\n\n        if (!nonDoor) {\n            // Build phase: all humans help build the non-door perimeter.\n            vector<Task> tasks = getNonDoorTasks();\n\n            vector<int> assignedTask(M, -1);\n            vector<int> usedTask(tasks.size(), 0);\n            vector<int> usedHuman(M, 0);\n\n            // First: immediate build opportunities.\n            for (int i = 0; i < M; ++i) {\n                for (int t = 0; t < (int)tasks.size(); ++t) {\n                    if (usedTask[t]) continue;\n                    if (hs0[i] == tasks[t].pos &&\n                        canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) {\n                        assignedTask[i] = t;\n                        usedTask[t] = 1;\n                        usedHuman[i] = 1;\n                        break;\n                    }\n                }\n            }\n\n            // Greedy assignment by distance.\n            struct Cand {\n                int d, i, t;\n                bool operator<(const Cand& o) const {\n                    if (d != o.d) return d < o.d;\n                    if (i != o.i) return i < o.i;\n                    return t < o.t;\n                }\n            };\n            vector<Cand> cand;\n            for (int i = 0; i < M; ++i) if (!usedHuman[i]) {\n                for (int t = 0; t < (int)tasks.size(); ++t) if (!usedTask[t]) {\n                    int d = manhattan(hs0[i], tasks[t].pos);\n                    if (hs0[i] == tasks[t].pos &&\n                        !canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) {\n                        d += 3; // discourage camping on temporarily blocked task\n                    }\n                    cand.push_back({d, i, t});\n                }\n            }\n            sort(cand.begin(), cand.end());\n            for (auto& c : cand) {\n                if (usedHuman[c.i] || usedTask[c.t]) continue;\n                usedHuman[c.i] = 1;\n                usedTask[c.t] = 1;\n                assignedTask[c.i] = c.t;\n            }\n\n            for (int i = 0; i < M; ++i) {\n                if (assignedTask[i] != -1) {\n                    auto& task = tasks[assignedTask[i]];\n                    if (hs0[i] == task.pos) {\n                        if (canBuildCell(task.wall.x, task.wall.y, hs0, ps0)) act[i] = task.act;\n                        else act[i] = '.';\n                    } else {\n                        act[i] = moveToward(hs0[i], task.pos);\n                    }\n                } else {\n                    act[i] = moveToward(hs0[i], parkTarget[i]);\n                }\n            }\n        } else if (!closedFully()) {\n            // Door control phase.\n            Pos corner = {Hrect, Wrect};\n            int closer = nearestHumanTo(corner, hs0);\n\n            // Everyone else just moves inside / parks.\n            for (int i = 0; i < M; ++i) {\n                if (i == closer) continue;\n                act[i] = moveToward(hs0[i], parkTarget[i]);\n            }\n\n            if (!doorDown && !doorRight) {\n                // Close one door immediately if possible.\n                // Keep the more useful door open for remaining outside humans.\n                long long costDown = 0, costRight = 0;\n                for (int i = 0; i < M; ++i) {\n                    if (hs0[i].x <= Hrect && hs0[i].y <= Wrect) continue;\n                    costDown += manhattan(hs0[i], {Hrect + 1, Wrect});\n                    costRight += manhattan(hs0[i], {Hrect, Wrect + 1});\n                }\n\n                bool preferCloseDown = (costDown > costRight); // keep easier door open\n                bool canDown = canBuildCell(Hrect + 1, Wrect, hs0, ps0);\n                bool canRight = canBuildCell(Hrect, Wrect + 1, hs0, ps0);\n\n                if (hs0[closer] != corner) {\n                    act[closer] = moveToward(hs0[closer], corner);\n                } else {\n                    if (preferCloseDown) {\n                        if (canDown) act[closer] = 'd';\n                        else if (canRight) act[closer] = 'r';\n                        else act[closer] = '.';\n                    } else {\n                        if (canRight) act[closer] = 'r';\n                        else if (canDown) act[closer] = 'd';\n                        else act[closer] = '.';\n                    }\n                }\n            } else {\n                // One door remains. Close it once all humans are inside and timing is good.\n                int pin = countPetsInside();\n                bool doClose = allIn && shouldCloseSecondDoor(turn, pin);\n\n                if (hs0[closer] != corner) {\n                    act[closer] = moveToward(hs0[closer], corner);\n                } else {\n                    if (doClose) {\n                        if (!doorDown && canBuildCell(Hrect + 1, Wrect, hs0, ps0)) act[closer] = 'd';\n                        else if (!doorRight && canBuildCell(Hrect, Wrect + 1, hs0, ps0)) act[closer] = 'r';\n                        else act[closer] = '.';\n                    } else {\n                        act[closer] = '.';\n                    }\n                }\n            }\n        } else {\n            // Fully closed.\n            for (int i = 0; i < M; ++i) act[i] = moveToward(hs0[i], parkTarget[i]);\n        }\n\n        // Sanitize build actions: legality and duplicate targets.\n        set<pair<int,int>> buildSet;\n        vector<Pos> buildTarget(M, {-1, -1});\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!canBuildCell(t.x, t.y, hs0, ps0)) {\n                    act[i] = '.';\n                    continue;\n                }\n                if (buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                    continue;\n                }\n                buildSet.insert({t.x, t.y});\n                buildTarget[i] = t;\n            }\n        }\n\n        // Sanitize move actions.\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!inside(t.x, t.y) || wallg[t.x][t.y] || buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        string out(M, '.');\n        for (int i = 0; i < M; ++i) out[i] = mapDirByCorner(act[i], chosenCorner);\n        cout << out << '\\n';\n        cout.flush();\n\n        // Update humans/walls after our action.\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (canBuildCell(t.x, t.y, hs0, ps0)) wallg[t.x][t.y] = true;\n            }\n        }\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (inside(t.x, t.y) && !wallg[t.x][t.y] && !buildSet.count({t.x, t.y})) {\n                    humans[i] = t;\n                }\n            }\n        }\n\n        // Read pet moves and update normalized positions.\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                if (c == '.') continue;\n                char nc = mapDirByCorner(c, chosenCorner);\n                pets[i] = addDir(pets[i], nc);\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 = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr char DIRS[4] = {'U', 'D', 'L', 'R'};\n\nint si, sj, ti, tj;\ndouble P, Q;\nstring hwall[N];\nstring vwall[N - 1];\n\nint start_id, target_id;\nint nxtPos[V][4];\ndouble adaptDP[MAXL + 2][V]; // adaptive-policy upper bound from step..MAXL\nint distToTarget[V];\n\ninline int id(int i, int j) { return i * N + j; }\ninline int r_of(int x) { return x / N; }\ninline int c_of(int x) { return x % N; }\n\ninline int dirIndex(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\n\nstruct State {\n    array<float, V> pr{};\n    array<char, MAXL> path{};\n    double score = 0.0;  // exact expected score already earned\n    double upper = 0.0;  // score + relaxed adaptive upper bound\n    double pri = 0.0;    // beam priority\n    int len = 0;\n};\n\nstring toString(const State& st) {\n    return string(st.path.begin(), st.path.begin() + st.len);\n}\n\nvoid buildTransitions() {\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int x = id(i, j);\n\n            // U\n            if (i == 0 || vwall[i - 1][j] == '1') nxtPos[x][0] = x;\n            else nxtPos[x][0] = id(i - 1, j);\n\n            // D\n            if (i == N - 1 || vwall[i][j] == '1') nxtPos[x][1] = x;\n            else nxtPos[x][1] = id(i + 1, j);\n\n            // L\n            if (j == 0 || hwall[i][j - 1] == '1') nxtPos[x][2] = x;\n            else nxtPos[x][2] = id(i, j - 1);\n\n            // R\n            if (j == N - 1 || hwall[i][j] == '1') nxtPos[x][3] = x;\n            else nxtPos[x][3] = id(i, j + 1);\n        }\n    }\n}\n\nvoid bfsDist() {\n    fill(distToTarget, distToTarget + V, (int)1e9);\n    queue<int> q;\n    distToTarget[target_id] = 0;\n    q.push(target_id);\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        int d = distToTarget[x];\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (distToTarget[y] > d + 1) {\n                distToTarget[y] = d + 1;\n                q.push(y);\n            }\n        }\n    }\n}\n\n// Relaxation: assume from each exact cell we may choose the next action adaptively.\n// This is an upper bound for the real open-loop problem.\nvoid buildAdaptiveDP() {\n    for (int x = 0; x < V; x++) adaptDP[MAXL + 1][x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        for (int x = 0; x < V; x++) {\n            if (x == target_id) {\n                adaptDP[step][x] = 0.0;\n                continue;\n            }\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int y = nxtPos[x][a];\n                double val = P * adaptDP[step + 1][x];\n                if (y == target_id) {\n                    val += Q * (401.0 - step);\n                } else {\n                    val += Q * adaptDP[step + 1][y];\n                }\n                if (val > best) best = val;\n            }\n            adaptDP[step][x] = best;\n        }\n    }\n}\n\nState initialState() {\n    State st;\n    st.pr.fill(0.0f);\n    st.pr[start_id] = 1.0f;\n    st.score = 0.0;\n    st.len = 0;\n    st.upper = adaptDP[1][start_id];\n    st.pri = st.upper + 4.0; // concentrated at one cell\n    return st;\n}\n\nState extendState(const State& st, int a, int step) {\n    State nx;\n    nx.pr.fill(0.0f);\n    nx.path = st.path;\n    nx.path[st.len] = DIRS[a];\n    nx.len = st.len + 1;\n    nx.score = st.score;\n\n    const double hitReward = 401.0 - step;\n\n    for (int x = 0; x < V; x++) {\n        float q = st.pr[x];\n        if (q < 1e-8f) continue;\n\n        int y = nxtPos[x][a];\n        if (y == target_id) {\n            float stay = q * (float)P;\n            if (stay > 0) nx.pr[x] += stay;\n            nx.score += (double)q * Q * hitReward;\n        } else if (y == x) {\n            nx.pr[x] += q;\n        } else {\n            float stay = q * (float)P;\n            float go = q * (float)Q;\n            if (stay > 0) nx.pr[x] += stay;\n            if (go > 0) nx.pr[y] += go;\n        }\n    }\n\n    double future = 0.0;\n    double sq = 0.0; // concentration bonus for ranking\n    int nextStep = step + 1;\n    for (int x = 0; x < V; x++) {\n        double p = nx.pr[x];\n        if (p < 1e-12) continue;\n        future += p * adaptDP[nextStep][x];\n        sq += p * p;\n    }\n\n    nx.upper = nx.score + future;\n    nx.pri = nx.upper + 6.0 * sq;\n    return nx;\n}\n\ndouble evaluateString(const string& s) {\n    array<double, V> cur{}, nxt{};\n    cur.fill(0.0);\n    cur[start_id] = 1.0;\n    double score = 0.0;\n\n    for (int step = 1; step <= (int)s.size(); step++) {\n        nxt.fill(0.0);\n        int a = dirIndex(s[step - 1]);\n        double hitReward = 401.0 - step;\n\n        for (int x = 0; x < V; x++) {\n            double q = cur[x];\n            if (q < 1e-14) continue;\n\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                nxt[x] += q * P;\n                score += q * Q * hitReward;\n            } else if (y == x) {\n                nxt[x] += q;\n            } else {\n                nxt[x] += q * P;\n                nxt[y] += q * Q;\n            }\n        }\n        cur.swap(nxt);\n    }\n\n    return score;\n}\n\nState applyPrefix(const string& s) {\n    State st = initialState();\n    for (int step = 1; step <= (int)s.size(); step++) {\n        st = extendState(st, dirIndex(s[step - 1]), step);\n    }\n    return st;\n}\n\nState greedyComplete(State cur) {\n    for (int step = cur.len + 1; step <= MAXL; step++) {\n        State best;\n        bool first = true;\n        for (int a = 0; a < 4; a++) {\n            State nx = extendState(cur, a, step);\n            if (first || nx.pri > best.pri + 1e-12 ||\n                (abs(nx.pri - best.pri) <= 1e-12 && nx.score > best.score)) {\n                best = std::move(nx);\n                first = false;\n            }\n        }\n        cur = std::move(best);\n    }\n    return cur;\n}\n\nstring shortestPathString() {\n    vector<int> prev(V, -1), prevDir(V, -1);\n    queue<int> q;\n    q.push(start_id);\n    prev[start_id] = start_id;\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        if (x == target_id) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (prev[y] == -1) {\n                prev[y] = x;\n                prevDir[y] = a;\n                q.push(y);\n            }\n        }\n    }\n\n    if (prev[target_id] == -1) return \"\";\n\n    string res;\n    int cur = target_id;\n    while (cur != start_id) {\n        res.push_back(DIRS[prevDir[cur]]);\n        cur = prev[cur];\n    }\n    reverse(res.begin(), res.end());\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> P;\n    Q = 1.0 - P;\n    for (int i = 0; i < N; i++) cin >> hwall[i];\n    for (int i = 0; i < N - 1; i++) cin >> vwall[i];\n\n    start_id = id(si, sj);\n    target_id = id(ti, tj);\n\n    auto timeStart = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - timeStart).count();\n    };\n\n    buildTransitions();\n    bfsDist();\n    buildAdaptiveDP();\n\n    double bestScore = -1.0;\n    string bestAns;\n\n    auto relaxBestState = [&](const State& st) {\n        if (st.len != MAXL) return;\n        if (st.score > bestScore + 1e-12) {\n            bestScore = st.score;\n            bestAns = toString(st);\n        }\n    };\n\n    auto relaxBestString = [&](const string& s) {\n        if ((int)s.size() != MAXL) return;\n        double sc = evaluateString(s);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    };\n\n    // Initial candidates\n    {\n        State init = initialState();\n        relaxBestState(greedyComplete(init));\n\n        string sp = shortestPathString();\n        if (!sp.empty()) {\n            // shortest path as prefix + greedy suffix\n            {\n                State pref = applyPrefix(sp.substr(0, min<int>(MAXL, sp.size())));\n                if (pref.len < MAXL) relaxBestState(greedyComplete(pref));\n                else relaxBestState(pref);\n            }\n\n            // repeated shortest-path variants\n            for (int baseK = 1; baseK <= 4; baseK++) {\n                for (int turnBonus = 0; turnBonus <= 1; turnBonus++) {\n                    string s;\n                    for (int i = 0; i < (int)sp.size() && (int)s.size() < MAXL; i++) {\n                        int rep = baseK;\n                        if (turnBonus && i + 1 < (int)sp.size() && sp[i] != sp[i + 1]) rep++;\n                        for (int k = 0; k < rep && (int)s.size() < MAXL; k++) s.push_back(sp[i]);\n                    }\n                    State pref = applyPrefix(s);\n                    if (pref.len < MAXL) relaxBestState(greedyComplete(pref));\n                    else relaxBestState(pref);\n                }\n            }\n        }\n    }\n\n    // Beam search\n    {\n        vector<State> beam, cand;\n        beam.reserve(500);\n        cand.reserve(2200);\n        beam.push_back(initialState());\n\n        auto cmpState = [](const State& a, const State& b) {\n            if (fabs(a.pri - b.pri) > 1e-12) return a.pri > b.pri;\n            if (fabs(a.upper - b.upper) > 1e-12) return a.upper > b.upper;\n            return a.score > b.score;\n        };\n\n        for (int step = 1; step <= MAXL; step++) {\n            if (elapsed() > 1.20) break;\n\n            int width;\n            if (step <= 50) width = 420;\n            else if (step <= 120) width = 300;\n            else width = 220;\n\n            cand.clear();\n\n            for (const State& st : beam) {\n                if (st.upper + 1e-12 < bestScore) continue;\n                for (int a = 0; a < 4; a++) {\n                    State nx = extendState(st, a, step);\n                    if (nx.upper + 1e-12 < bestScore) continue;\n                    cand.push_back(std::move(nx));\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(cand.begin(), cand.begin() + width, cand.end(), cmpState);\n                cand.resize(width);\n            }\n            sort(cand.begin(), cand.end(), cmpState);\n            beam.swap(cand);\n\n            if (!beam.empty() && (step <= 20 || step % 8 == 0)) {\n                int tries = min<int>((step <= 20 ? 3 : 2), beam.size());\n                for (int i = 0; i < tries; i++) {\n                    State g = greedyComplete(beam[i]);\n                    relaxBestState(g);\n                }\n            }\n        }\n\n        for (const State& st : beam) {\n            if (st.len == MAXL) relaxBestState(st);\n        }\n        if (!beam.empty() && elapsed() < 1.35) {\n            int tries = min<int>(5, beam.size());\n            for (int i = 0; i < tries; i++) {\n                State g = greedyComplete(beam[i]);\n                relaxBestState(g);\n            }\n        }\n    }\n\n    if (bestAns.empty()) {\n        State g = greedyComplete(initialState());\n        bestAns = toString(g);\n        bestScore = g.score;\n    }\n\n    // Regrow local search:\n    // Change one action at position i, then greedily rebuild the suffix.\n    {\n        int pass = 0;\n        while (elapsed() < 1.82 && pass < 3) {\n            pass++;\n            bool improved = false;\n\n            State prefix = initialState();\n            for (int i = 0; i < MAXL && elapsed() < 1.82; i++) {\n                int orig = dirIndex(bestAns[i]);\n\n                for (int a = 0; a < 4; a++) {\n                    if (a == orig) continue;\n\n                    State nx = extendState(prefix, a, i + 1);\n                    if (nx.upper + 1e-12 < bestScore) continue;\n\n                    State g = greedyComplete(nx);\n                    if (g.score > bestScore + 1e-12) {\n                        bestScore = g.score;\n                        bestAns = toString(g);\n                        improved = true;\n                    }\n                }\n\n                if (improved) break;\n                prefix = extendState(prefix, orig, i + 1);\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    // Final exact hill climbing with fixed suffix\n    {\n        int pass = 0;\n        while (elapsed() < 1.96 && pass < 2) {\n            pass++;\n            bool improved = false;\n            for (int i = 0; i < MAXL && elapsed() < 1.96; i++) {\n                char old = bestAns[i];\n                char bestC = old;\n                double localBest = bestScore;\n\n                for (char c : DIRS) {\n                    if (c == old) continue;\n                    bestAns[i] = c;\n                    double sc = evaluateString(bestAns);\n                    if (sc > localBest + 1e-12) {\n                        localBest = sc;\n                        bestC = c;\n                    }\n                }\n                bestAns[i] = bestC;\n                if (localBest > bestScore + 1e-12) {\n                    bestScore = localBest;\n                    improved = true;\n                } else {\n                    bestAns[i] = old;\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc010":"#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    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int CELLS = N * N;\nstatic constexpr int SIDES = CELLS * 4;\n\nstatic constexpr int di[4] = {0, -1, 0, 1};\nstatic constexpr int dj[4] = {-1, 0, 1, 0};\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\n// rotation by 90 degrees counterclockwise\nstatic constexpr int ROT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\n\n// partner[ state ][ entering-side ] = leaving-side, -1 if unused\nstatic constexpr int PARTNER[8][4] = {\n    {1, 0, -1, -1},   // 0\n    {3, -1, -1, 0},   // 1\n    {-1, -1, 3, 2},   // 2\n    {-1, 2, 1, -1},   // 3\n    {1, 0, 3, 2},     // 4\n    {3, 2, 1, 0},     // 5\n    {2, -1, 0, -1},   // 6\n    {-1, 3, -1, 1},   // 7\n};\n\nstruct Eval {\n    long long score = 0;   // official score = top1 * top2 (or 0)\n    long long aux = 0;     // search objective\n    long long sumsq = 0;\n    int top1 = 0, top2 = 0;\n    int loops = 0;\n    int conn = 0;          // local connectivity score\n};\n\nstruct CandidateState {\n    array<uint8_t, CELLS> st{};\n    Eval ev;\n};\n\nstruct Solver {\n    array<string, N> input{};\n    array<uint8_t, CELLS> orig{};\n    uint8_t cand[CELLS][4]{};\n    uint8_t candCnt[CELLS]{};\n    int rotTo[8][8];\n    int mask[8];\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n    const double TIME_LIMIT = 1.95;\n\n    Solver() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng = XorShift64(seed);\n\n        memset(rotTo, -1, sizeof(rotTo));\n        for (int t = 0; t < 8; t++) {\n            int cur = t;\n            for (int k = 0; k < 4; k++) {\n                if (rotTo[t][cur] == -1) rotTo[t][cur] = k;\n                cur = ROT[cur];\n            }\n        }\n\n        for (int s = 0; s < 8; s++) {\n            int m = 0;\n            for (int d = 0; d < 4; d++) if (PARTNER[s][d] != -1) m |= (1 << d);\n            mask[s] = m;\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void read_input() {\n        for (int i = 0; i < N; i++) cin >> input[i];\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                orig[idx] = (uint8_t)(input[i][j] - '0');\n                int t = orig[idx];\n                if (0 <= t && t <= 3) {\n                    candCnt[idx] = 4;\n                    cand[idx][0] = 0;\n                    cand[idx][1] = 1;\n                    cand[idx][2] = 2;\n                    cand[idx][3] = 3;\n                } else if (t == 4 || t == 5) {\n                    candCnt[idx] = 2;\n                    cand[idx][0] = 4;\n                    cand[idx][1] = 5;\n                } else {\n                    candCnt[idx] = 2;\n                    cand[idx][0] = 6;\n                    cand[idx][1] = 7;\n                }\n            }\n        }\n    }\n\n    inline void addEdge(int u, int v, int deg[], int adj[][2]) const {\n        adj[u][deg[u]++] = v;\n        adj[v][deg[v]++] = u;\n    }\n\n    Eval evaluate(const array<uint8_t, CELLS>& st) const {\n        static int deg[SIDES];\n        static int adj[SIDES][2];\n        static uint8_t vis[SIDES];\n\n        for (int x = 0; x < SIDES; x++) {\n            deg[x] = -1;\n            vis[x] = 0;\n        }\n\n        Eval res;\n\n        // initialize used side nodes + tile internal edges + boundary penalties\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                int s = st[c];\n                int m = mask[s];\n\n                for (int d = 0; d < 4; d++) {\n                    int id = c * 4 + d;\n                    if (m & (1 << d)) deg[id] = 0;\n                }\n\n                for (int d = 0; d < 4; d++) {\n                    int p = PARTNER[s][d];\n                    if (p != -1 && d < p) {\n                        addEdge(c * 4 + d, c * 4 + p, deg, adj);\n                    }\n                }\n\n                if (j == 0     && (m & (1 << 0))) res.conn -= 3;\n                if (i == 0     && (m & (1 << 1))) res.conn -= 3;\n                if (j == N - 1 && (m & (1 << 2))) res.conn -= 3;\n                if (i == N - 1 && (m & (1 << 3))) res.conn -= 3;\n            }\n        }\n\n        // neighbor edges + local connectivity score\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j + 1 < N; j++) {\n                int a = i * N + j;\n                int b = i * N + (j + 1);\n                bool ua = (mask[st[a]] >> 2) & 1; // right\n                bool ub = (mask[st[b]] >> 0) & 1; // left\n                if (ua && ub) {\n                    addEdge(a * 4 + 2, b * 4 + 0, deg, adj);\n                    res.conn += 2;\n                } else if (ua ^ ub) {\n                    res.conn -= 3;\n                }\n            }\n        }\n        for (int i = 0; i + 1 < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int a = i * N + j;\n                int b = (i + 1) * N + j;\n                bool ua = (mask[st[a]] >> 3) & 1; // down\n                bool ub = (mask[st[b]] >> 1) & 1; // up\n                if (ua && ub) {\n                    addEdge(a * 4 + 3, b * 4 + 1, deg, adj);\n                    res.conn += 2;\n                } else if (ua ^ ub) {\n                    res.conn -= 3;\n                }\n            }\n        }\n\n        // find cycle components\n        static int q[SIDES];\n        for (int v = 0; v < SIDES; v++) {\n            if (deg[v] == -1 || vis[v]) continue;\n            int head = 0, tail = 0;\n            q[tail++] = v;\n            vis[v] = 1;\n\n            int cnt = 0;\n            bool all2 = true;\n\n            while (head < tail) {\n                int u = q[head++];\n                cnt++;\n                if (deg[u] != 2) all2 = false;\n                for (int k = 0; k < deg[u]; k++) {\n                    int to = adj[u][k];\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[tail++] = to;\n                    }\n                }\n            }\n\n            if (all2) {\n                int len = cnt / 2;\n                res.loops++;\n                res.sumsq += 1LL * len * len;\n                if (len > res.top1) {\n                    res.top2 = res.top1;\n                    res.top1 = len;\n                } else if (len > res.top2) {\n                    res.top2 = len;\n                }\n            }\n        }\n\n        if (res.loops >= 2) res.score = 1LL * res.top1 * res.top2;\n        else res.score = 0;\n\n        // official score first, then sumsq, then local consistency\n        res.aux = res.score * 1000000LL + res.sumsq * 100LL + res.conn;\n        return res;\n    }\n\n    inline bool betterFinal(const Eval& a, const Eval& b) const {\n        if (a.score != b.score) return a.score > b.score;\n        return a.aux > b.aux;\n    }\n\n    inline bool betterAux(const Eval& a, const Eval& b) const {\n        return a.aux > b.aux;\n    }\n\n    int localCellScore(const array<uint8_t, CELLS>& st, int pos, int ns) const {\n        int i = pos / N;\n        int j = pos % N;\n        int m = mask[ns];\n        int sc = 0;\n        for (int d = 0; d < 4; d++) {\n            bool used = (m >> d) & 1;\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (used) sc -= 3;\n            } else {\n                int np = ni * N + nj;\n                bool nused = (mask[st[np]] >> opp[d]) & 1;\n                if (used && nused) sc += 2;\n                else if (used ^ nused) sc -= 3;\n            }\n        }\n        return sc;\n    }\n\n    void localImprove(array<uint8_t, CELLS>& st, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                int pos = order[ii];\n                int cur = st[pos];\n                int bestState = cur;\n                int bestScore = localCellScore(st, pos, cur);\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    int ns = cand[pos][k];\n                    if (ns == cur) continue;\n                    int sc = localCellScore(st, pos, ns);\n                    if (sc > bestScore || (sc == bestScore && rng.next_int(2) == 0)) {\n                        bestScore = sc;\n                        bestState = ns;\n                    }\n                }\n                if (bestState != cur) {\n                    st[pos] = (uint8_t)bestState;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void exactDescent(array<uint8_t, CELLS>& st, Eval& cur, int maxSweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < maxSweeps; sw++) {\n            if (elapsed() > TIME_LIMIT) return;\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                if (elapsed() > TIME_LIMIT) return;\n                int pos = order[ii];\n\n                uint8_t origState = st[pos];\n                uint8_t bestState = origState;\n                Eval bestEval = cur;\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == origState) continue;\n                    st[pos] = ns;\n                    Eval ev = evaluate(st);\n                    if (betterAux(ev, bestEval)) {\n                        bestEval = ev;\n                        bestState = ns;\n                    }\n                }\n\n                st[pos] = bestState;\n                if (bestState != origState) {\n                    cur = bestEval;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void addSeed(vector<CandidateState>& seeds, const CandidateState& c) const {\n        seeds.push_back(c);\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n        if ((int)seeds.size() > 4) seeds.resize(4);\n    }\n\n    string solve() {\n        start_time = chrono::steady_clock::now();\n\n        vector<CandidateState> seeds;\n\n        // seed 0: original orientation\n        {\n            CandidateState c;\n            c.st = orig;\n            localImprove(c.st, 6);\n            c.ev = evaluate(c.st);\n            addSeed(seeds, c);\n        }\n\n        // random seeds\n        while (elapsed() < 0.35) {\n            CandidateState c;\n            for (int p = 0; p < CELLS; p++) {\n                c.st[p] = cand[p][rng.next_int(candCnt[p])];\n            }\n            localImprove(c.st, 8);\n            c.ev = evaluate(c.st);\n            addSeed(seeds, c);\n        }\n\n        // refine top seeds\n        for (int i = 0; i < (int)seeds.size(); i++) {\n            if (elapsed() > 0.90) break;\n            exactDescent(seeds[i].st, seeds[i].ev, 2);\n        }\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n\n        // iterative perturb + repair\n        while (elapsed() < TIME_LIMIT) {\n            int baseId = rng.next_int((int)seeds.size());\n            CandidateState cur = seeds[baseId];\n\n            int k = 4 + rng.next_int(18);\n            for (int t = 0; t < k; t++) {\n                int pos = rng.next_int(CELLS);\n                if (candCnt[pos] == 1) continue;\n                uint8_t now = cur.st[pos];\n                uint8_t ns = now;\n                for (int tries = 0; tries < 5 && ns == now; tries++) {\n                    ns = cand[pos][rng.next_int(candCnt[pos])];\n                }\n                cur.st[pos] = ns;\n            }\n\n            localImprove(cur.st, 2);\n            cur.ev = evaluate(cur.st);\n            exactDescent(cur.st, cur.ev, 1);\n\n            if (betterFinal(cur.ev, seeds[0].ev)) {\n                addSeed(seeds, cur);\n            } else {\n                // even if not best, keep some diversity\n                addSeed(seeds, cur);\n            }\n        }\n\n        sort(seeds.begin(), seeds.end(), [&](const CandidateState& a, const CandidateState& b) {\n            return betterFinal(a.ev, b.ev);\n        });\n        const auto& best = seeds[0].st;\n\n        string ans;\n        ans.reserve(CELLS);\n        for (int p = 0; p < CELLS; p++) {\n            int t = orig[p];\n            int s = best[p];\n            int r = rotTo[t][s];\n            if (r < 0) r = 0; // should not happen\n            ans.push_back(char('0' + r));\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXM = 100;\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\nuint64_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 XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) { // [l, r)\n        return l + (int)(next() % (uint64_t)(r - l));\n    }\n};\n\nint hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nchar opposite(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    if (c == 'R') return 'L';\n    return 0;\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int largestCC = 0;\n    int largestCCCycles = 0;\n    int cycleExcess = 0;\n    int stubs = 0;\n    int matchedEdges = 0;\n    int bestPotential = 0; // max over components of (4*v - 7*c)\n};\n\nstruct State {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    Metrics mt;\n};\n\nstruct Cand {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    Metrics mt;\n};\n\nstruct BestRef {\n    bool isTemp = false;\n    int nodeIdx = 0;\n    int parent = -1;\n    char lastMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Elite {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    char prevMove = 0;\n    int depth = 0;\n    string prefix;\n    Metrics mt;\n};\n\nMetrics evaluateBoard(const array<uint8_t, MAXM>& board, int N) {\n    static int pop4[16] = {\n        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4\n    };\n    int M = N * N;\n\n    static int md[MAXM];\n    static unsigned char vis[MAXM];\n    memset(md, 0, sizeof(int) * M);\n    memset(vis, 0, M);\n\n    int degreeSum = 0;\n    int matchedHalf = 0;\n\n    auto hasMatch = [&](int id, int nid, int dirBit, int oppBit) -> bool {\n        return board[id] != 0 && board[nid] != 0 && (board[id] & dirBit) && (board[nid] & oppBit);\n    };\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            uint8_t t = board[id];\n            if (t == 0) continue;\n            degreeSum += pop4[t];\n\n            if (c > 0 && hasMatch(id, id - 1, 1, 4)) md[id]++;\n            if (r > 0 && hasMatch(id, id - N, 2, 8)) md[id]++;\n            if (c + 1 < N && hasMatch(id, id + 1, 4, 1)) md[id]++;\n            if (r + 1 < N && hasMatch(id, id + N, 8, 2)) md[id]++;\n            matchedHalf += md[id];\n        }\n    }\n\n    Metrics mt;\n    mt.matchedEdges = matchedHalf / 2;\n    mt.stubs = degreeSum - matchedHalf;\n\n    static int q[MAXM];\n    for (int s = 0; s < M; s++) {\n        if (board[s] == 0 || vis[s]) continue;\n\n        int head = 0, tail = 0;\n        q[tail++] = s;\n        vis[s] = 1;\n\n        int v = 0;\n        int sumMd = 0;\n\n        while (head < tail) {\n            int u = q[head++];\n            v++;\n            sumMd += md[u];\n            int r = u / N, c = u % N;\n\n            if (c > 0 && !vis[u - 1] && hasMatch(u, u - 1, 1, 4)) {\n                vis[u - 1] = 1;\n                q[tail++] = u - 1;\n            }\n            if (r > 0 && !vis[u - N] && hasMatch(u, u - N, 2, 8)) {\n                vis[u - N] = 1;\n                q[tail++] = u - N;\n            }\n            if (c + 1 < N && !vis[u + 1] && hasMatch(u, u + 1, 4, 1)) {\n                vis[u + 1] = 1;\n                q[tail++] = u + 1;\n            }\n            if (r + 1 < N && !vis[u + N] && hasMatch(u, u + N, 8, 2)) {\n                vis[u + N] = 1;\n                q[tail++] = u + N;\n            }\n        }\n\n        int e = sumMd / 2;\n        int cyc = max(0, e - v + 1);\n        mt.cycleExcess += cyc;\n\n        if (e == v - 1) mt.largestTree = max(mt.largestTree, v);\n\n        if (v > mt.largestCC || (v == mt.largestCC && cyc < mt.largestCCCycles)) {\n            mt.largestCC = v;\n            mt.largestCCCycles = cyc;\n        }\n\n        mt.bestPotential = max(mt.bestPotential, 4 * v - 7 * cyc);\n    }\n\n    return mt;\n}\n\nbool betterReal(const Metrics& a, int depthA, const Metrics& b, int depthB, int fullSize) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestTree == fullSize && depthA != depthB) return depthA < depthB;\n    if (a.bestPotential != b.bestPotential) return a.bestPotential > b.bestPotential;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.stubs != b.stubs) return a.stubs < b.stubs;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    return false;\n}\n\nlong long beamKey(const Metrics& m, int depth, int T) {\n    // Early: value large, almost-tree-like connected components.\n    // Late: value actual tree size and cycle reduction.\n    if (depth * 100 < T * 55) {\n        return 1'000'000'000LL * m.bestPotential\n             + 1'000'000LL * m.largestCC\n             - 10'000LL * m.largestCCCycles\n             + 100LL * m.largestTree\n             - m.stubs;\n    } else {\n        return 1'000'000'000LL * m.largestTree\n             + 1'000'000LL * m.bestPotential\n             + 10'000LL * m.largestCC\n             - 100LL * m.cycleExcess\n             - m.stubs;\n    }\n}\n\nlong long rolloutKey(const Metrics& m) {\n    return 1'000'000LL * m.largestTree\n         + 200'000LL * m.bestPotential\n         + 5'000LL * m.largestCC\n         - 2'000LL * m.cycleExcess\n         - 20LL * m.stubs\n         + 10LL * m.matchedEdges;\n}\n\nstring reconstructPathFromNode(const vector<State>& nodes, int idx) {\n    string s;\n    while (idx > 0) {\n        s.push_back(nodes[idx].prevMove);\n        idx = nodes[idx].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nvoid applyMoveInPlace(array<uint8_t, MAXM>& board, int& empty, char mv) {\n    int np = -1;\n    // Move adjacent tile in direction mv into empty.\n    if (mv == 'U') np = empty - 10; // dummy\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    cin >> N >> T;\n    int M = N * N;\n    int FULL = M - 1;\n\n    array<uint8_t, MAXM> initBoard{};\n    int initEmpty = -1;\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            initBoard[i * N + j] = (uint8_t)v;\n            if (v == 0) initEmpty = i * N + j;\n        }\n    }\n\n    uint64_t zob[MAXM][16];\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < MAXM; i++) {\n        for (int j = 0; j < 16; j++) {\n            seed = splitmix64(seed);\n            zob[i][j] = seed;\n        }\n    }\n\n    uint64_t initHash = 0;\n    for (int i = 0; i < M; i++) initHash ^= zob[i][initBoard[i]];\n\n    Timer timer;\n    XorShift64 rng(initHash ^ 0x9e3779b97f4a7c15ULL);\n\n    State root;\n    root.board = initBoard;\n    root.hash = initHash;\n    root.empty = initEmpty;\n    root.parent = -1;\n    root.prevMove = 0;\n    root.mt = evaluateBoard(root.board, N);\n\n    if (root.mt.largestTree == FULL) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    int beamWidth;\n    if (N <= 7) beamWidth = 320;\n    else if (N == 8) beamWidth = 260;\n    else if (N == 9) beamWidth = 220;\n    else beamWidth = 180;\n\n    vector<State> nodes;\n    nodes.reserve(1 + beamWidth * (T + 2));\n    nodes.push_back(root);\n\n    vector<int> cur, nxt;\n    cur.push_back(0);\n\n    BestRef best;\n    best.isTemp = false;\n    best.nodeIdx = 0;\n    best.depth = 0;\n    best.mt = root.mt;\n\n    const char moves[4] = {'U', 'D', 'L', 'R'};\n\n    double beamTimeLimit = 2.55;\n    if (N <= 7) beamTimeLimit = 2.65;\n\n    for (int depth = 0; depth < T; depth++) {\n        if (timer.elapsed() > beamTimeLimit) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool foundFull = false;\n\n        for (int idx : cur) {\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                Cand cd;\n                cd.board = st.board;\n                uint8_t tile = cd.board[np];\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.hash = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                cd.mt = evaluateBoard(cd.board, N);\n\n                if (betterReal(cd.mt, depth + 1, best.mt, best.depth, FULL)) {\n                    best.isTemp = true;\n                    best.parent = idx;\n                    best.lastMove = mv;\n                    best.depth = depth + 1;\n                    best.mt = cd.mt;\n                }\n\n                if (cd.mt.largestTree == FULL) {\n                    foundFull = true;\n                    break;\n                }\n\n                auto it = seen.find(cd.hash);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(cd.hash, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (beamKey(cd.mt, depth + 1, T) > beamKey(cands[pos].mt, depth + 1, T)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n            if (foundFull) break;\n        }\n\n        if (best.mt.largestTree == FULL) break;\n        if (cands.empty()) break;\n\n        auto cmpBeam = [&](const Cand& a, const Cand& b) {\n            long long ka = beamKey(a.mt, depth + 1, T);\n            long long kb = beamKey(b.mt, depth + 1, T);\n            if (ka != kb) return ka > kb;\n            if (a.mt.stubs != b.mt.stubs) return a.mt.stubs < b.mt.stubs;\n            return a.mt.matchedEdges > b.mt.matchedEdges;\n        };\n\n        sort(cands.begin(), cands.end(), cmpBeam);\n\n        nxt.clear();\n        nxt.reserve(min((int)cands.size(), beamWidth));\n\n        int perEmptyLimit = 4;\n        vector<int> emptyCnt(M, 0);\n\n        // first pass: with diversity\n        for (auto& cd : cands) {\n            if ((int)nxt.size() >= beamWidth) break;\n            if (emptyCnt[cd.empty] >= perEmptyLimit) continue;\n\n            State ns;\n            ns.board = cd.board;\n            ns.hash = cd.hash;\n            ns.empty = cd.empty;\n            ns.parent = cd.parent;\n            ns.prevMove = cd.prevMove;\n            ns.mt = cd.mt;\n            int nid = (int)nodes.size();\n            nodes.push_back(std::move(ns));\n            nxt.push_back(nid);\n            emptyCnt[cd.empty]++;\n\n            if (betterReal(nodes[nid].mt, depth + 1, best.mt, best.depth, FULL)) {\n                best.isTemp = false;\n                best.nodeIdx = nid;\n                best.depth = depth + 1;\n                best.mt = nodes[nid].mt;\n            }\n        }\n\n        // second pass: fill if not enough\n        if ((int)nxt.size() < beamWidth) {\n            for (auto& cd : cands) {\n                if ((int)nxt.size() >= beamWidth) break;\n\n                State ns;\n                ns.board = cd.board;\n                ns.hash = cd.hash;\n                ns.empty = cd.empty;\n                ns.parent = cd.parent;\n                ns.prevMove = cd.prevMove;\n                ns.mt = cd.mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n\n                if (betterReal(nodes[nid].mt, depth + 1, best.mt, best.depth, FULL)) {\n                    best.isTemp = false;\n                    best.nodeIdx = nid;\n                    best.depth = depth + 1;\n                    best.mt = nodes[nid].mt;\n                }\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    auto materializeTempBest = [&](const BestRef& b) -> Elite {\n        Elite e;\n        const State& p = nodes[b.parent];\n        e.board = p.board;\n        e.hash = p.hash;\n        e.empty = p.empty;\n        e.prevMove = b.lastMove;\n        e.depth = b.depth;\n        e.prefix = reconstructPathFromNode(nodes, b.parent);\n        e.prefix.push_back(b.lastMove);\n\n        int empty = p.empty;\n        int np = -1;\n        int r = empty / N, c = empty % N;\n        if (b.lastMove == 'U') np = empty - N;\n        else if (b.lastMove == 'D') np = empty + N;\n        else if (b.lastMove == 'L') np = empty - 1;\n        else np = empty + 1;\n\n        uint8_t tile = e.board[np];\n        e.board[empty] = tile;\n        e.board[np] = 0;\n        e.empty = np;\n        e.hash = p.hash ^ zob[empty][0] ^ zob[np][tile] ^ zob[empty][tile] ^ zob[np][0];\n        e.mt = b.mt;\n        return e;\n    };\n\n    auto nodeToElite = [&](int idx) -> Elite {\n        Elite e;\n        const State& s = nodes[idx];\n        e.board = s.board;\n        e.hash = s.hash;\n        e.empty = s.empty;\n        e.prevMove = s.prevMove;\n        e.depth = 0;\n        e.prefix = reconstructPathFromNode(nodes, idx);\n        e.depth = (int)e.prefix.size();\n        e.mt = s.mt;\n        return e;\n    };\n\n    string bestAns;\n    if (best.isTemp) {\n        bestAns = reconstructPathFromNode(nodes, best.parent);\n        bestAns.push_back(best.lastMove);\n    } else {\n        bestAns = reconstructPathFromNode(nodes, best.nodeIdx);\n    }\n\n    if (best.mt.largestTree == FULL) {\n        if ((int)bestAns.size() > T) bestAns.resize(T);\n        cout << bestAns << '\\n';\n        return 0;\n    }\n\n    // Collect elite states for rollout\n    vector<pair<long long, int>> ord;\n    ord.reserve(cur.size());\n    for (int idx : cur) {\n        ord.push_back({rolloutKey(nodes[idx].mt), idx});\n    }\n    sort(ord.begin(), ord.end(), greater<>());\n\n    vector<Elite> elites;\n    int eliteLimit = min(10, (int)ord.size());\n    for (int i = 0; i < eliteLimit; i++) {\n        elites.push_back(nodeToElite(ord[i].second));\n    }\n\n    if (best.isTemp) {\n        elites.push_back(materializeTempBest(best));\n    } else {\n        elites.push_back(nodeToElite(best.nodeIdx));\n    }\n\n    // Deduplicate elites by hash/prefix depth roughly\n    vector<Elite> uniq;\n    unordered_set<uint64_t> eliteSeen;\n    eliteSeen.reserve(elites.size() * 2 + 8);\n    for (auto& e : elites) {\n        if (eliteSeen.insert(e.hash).second) uniq.push_back(std::move(e));\n    }\n    elites.swap(uniq);\n\n    const double totalTimeLimit = 2.93;\n\n    struct Opt {\n        array<uint8_t, MAXM> board{};\n        uint64_t hash = 0;\n        int empty = 0;\n        char mv = 0;\n        Metrics mt;\n        long long key = 0;\n    };\n\n    while (timer.elapsed() < totalTimeLimit && !elites.empty()) {\n        const Elite& base = elites[rng.next_int(0, (int)elites.size())];\n\n        array<uint8_t, MAXM> board = base.board;\n        uint64_t hash = base.hash;\n        int empty = base.empty;\n        char prevMove = base.prevMove;\n        string suffix;\n        suffix.reserve(max(0, T - base.depth));\n\n        Metrics curMt = base.mt;\n\n        uint64_t recent[16];\n        int recentLen = 0;\n        int recentPos = 0;\n        recent[recentLen++] = hash;\n\n        int stagnation = 0;\n        long long curKey = rolloutKey(curMt);\n\n        while (base.depth + (int)suffix.size() < T && timer.elapsed() < totalTimeLimit) {\n            vector<Opt> opts;\n            opts.reserve(4);\n\n            int r = empty / N, c = empty % N;\n            for (char mv : moves) {\n                if (prevMove && mv == opposite(prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = empty - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = empty + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = empty - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = empty + 1;\n                }\n\n                Opt op;\n                op.board = board;\n                uint8_t tile = op.board[np];\n                op.board[empty] = tile;\n                op.board[np] = 0;\n                op.empty = np;\n                op.mv = mv;\n                op.hash = hash ^ zob[empty][0] ^ zob[np][tile] ^ zob[empty][tile] ^ zob[np][0];\n                op.mt = evaluateBoard(op.board, N);\n                op.key = rolloutKey(op.mt);\n\n                bool revisited = false;\n                for (int i = 0; i < recentLen; i++) {\n                    if (recent[i] == op.hash) {\n                        revisited = true;\n                        break;\n                    }\n                }\n                if (revisited) op.key -= 50'000;\n\n                // slight randomization\n                op.key += (long long)(rng.next() % 2001) - 1000;\n                opts.push_back(std::move(op));\n            }\n\n            if (opts.empty()) break;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.key > b.key; });\n\n            int pick = 0;\n            uint64_t rv = rng.next() % 100;\n            if ((int)opts.size() >= 3) {\n                if (rv < 72) pick = 0;\n                else if (rv < 92) pick = 1;\n                else pick = 2;\n            } else if ((int)opts.size() == 2) {\n                if (rv < 78) pick = 0;\n                else pick = 1;\n            }\n\n            // If stagnating, occasionally force non-best move\n            if (stagnation >= 20 && (int)opts.size() >= 2 && (rng.next() & 3) == 0) {\n                pick = 1;\n            }\n\n            Opt chosen = std::move(opts[pick]);\n            board = chosen.board;\n            hash = chosen.hash;\n            empty = chosen.empty;\n            prevMove = chosen.mv;\n            suffix.push_back(chosen.mv);\n\n            recent[recentPos] = hash;\n            recentPos = (recentPos + 1) & 15;\n            if (recentLen < 16) recentLen++;\n\n            long long nk = rolloutKey(chosen.mt);\n            if (nk > curKey) stagnation = 0;\n            else stagnation++;\n            curKey = nk;\n            curMt = chosen.mt;\n\n            int totalDepth = base.depth + (int)suffix.size();\n            if (betterReal(curMt, totalDepth, best.mt, best.depth, FULL)) {\n                best.isTemp = false;\n                best.nodeIdx = -1;\n                best.depth = totalDepth;\n                best.mt = curMt;\n                bestAns = base.prefix + suffix;\n                if (best.mt.largestTree == FULL) {\n                    if ((int)bestAns.size() > T) bestAns.resize(T);\n                    cout << bestAns << '\\n';\n                    return 0;\n                }\n            }\n        }\n    }\n\n    if ((int)bestAns.size() > T) bestAns.resize(T);\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr double R = 10000.0;\nstatic constexpr int MAXD = 10;\n\nstruct Point {\n    int x, y;\n};\n\nstruct BestSol {\n    int score = -1;\n    int goodCells = -1;\n    int dx = 1, dy = 0;   // primitive direction vector of family 1 lines\n    int m1 = 1, m2 = 1;   // number of strips in the two directions\n    double f1 = 0.5, f2 = 0.5; // offset fractions in (0,1)\n};\n\nstatic inline bool betterScore(int sc, int good, const BestSol& best) {\n    if (sc != best.score) return sc > best.score;\n    return good > best.goodCells;\n}\n\nlong long extgcd_pos(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = 1; y = 0;\n        return a;\n    }\n    long long x1, y1;\n    long long g = extgcd_pos(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\nstatic inline int calc_bin(double v, int m, double w, double f) {\n    if (m == 1) return 0;\n    double o = w * f;\n    double first = -R + o; // first cut\n    if (v < first) return 0;\n    int b = 1 + (int)((v - first) / w + 1e-12);\n    if (b >= m - 1) b = m - 1;\n    return b;\n}\n\nstruct EvalResult {\n    int score;\n    int goodCells;\n};\n\nEvalResult evaluate_grid(\n    const vector<double>& s,\n    const vector<double>& t,\n    int m1, int m2,\n    double f1, double f2,\n    const array<int, 11>& a\n) {\n    static int cnt[3005];\n    static int hist[11];\n    int cells = m1 * m2;\n    for (int i = 0; i < cells; i++) cnt[i] = 0;\n    for (int d = 0; d <= 10; d++) hist[d] = 0;\n\n    double w1 = 2.0 * R / m1;\n    double w2 = 2.0 * R / m2;\n\n    int N = (int)s.size();\n    for (int i = 0; i < N; i++) {\n        int b1 = calc_bin(s[i], m1, w1, f1);\n        int b2 = calc_bin(t[i], m2, w2, f2);\n        cnt[b1 * m2 + b2]++;\n    }\n\n    int good = 0;\n    for (int i = 0; i < cells; i++) {\n        int c = cnt[i];\n        if (1 <= c && c <= 10) {\n            hist[c]++;\n            good++;\n        }\n    }\n\n    int score = 0;\n    for (int d = 1; d <= 10; d++) score += min(a[d], hist[d]);\n    return {score, good};\n}\n\npair<int,int> normalize_dir(int dx, int dy) {\n    if (dx == 0 && dy == 0) return {1, 0};\n    int g = std::gcd(abs(dx), abs(dy));\n    dx /= g; dy /= g;\n    if (dx < 0 || (dx == 0 && dy < 0)) {\n        dx = -dx;\n        dy = -dy;\n    }\n    return {dx, dy};\n}\n\nvector<pair<int,int>> generate_dirs() {\n    const double PI = acos(-1.0);\n    const int L = 199;\n    set<pair<int,int>> st;\n\n    for (int i = 0; i < 30; i++) {\n        double ang = PI * i / 30.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        auto p = normalize_dir(dx, dy);\n        st.insert(p);\n    }\n\n    // Add a few simple directions explicitly\n    vector<pair<int,int>> extra = {\n        {1,0}, {0,1}, {1,1}, {2,1}, {1,2}, {3,1}, {1,3}\n    };\n    for (auto [dx,dy] : extra) st.insert(normalize_dir(dx,dy));\n\n    return vector<pair<int,int>>(st.begin(), st.end());\n}\n\nvector<double> select_lambdas(int N, const array<int,11>& a) {\n    vector<pair<double,double>> cand; // (approxScore, lambda)\n    for (double lam = 0.8; lam <= 10.0 + 1e-9; lam += 0.2) {\n        double Mocc = N / lam;\n        double p = exp(-lam);\n        double score = 0.0;\n        double cur = p;\n        for (int d = 1; d <= 10; d++) {\n            cur *= lam / d;\n            double bd = Mocc * cur;\n            score += min<double>(a[d], bd);\n        }\n        cand.push_back({score, lam});\n    }\n    sort(cand.begin(), cand.end(), [&](auto &l, auto &r) {\n        return l.first > r.first;\n    });\n\n    vector<double> res;\n    for (auto [sc, lam] : cand) {\n        bool ok = true;\n        for (double x : res) {\n            if (abs(x - lam) < 0.35) { ok = false; break; }\n        }\n        if (ok) res.push_back(lam);\n        if ((int)res.size() >= 5) break;\n    }\n\n    // fallback\n    if (res.empty()) res.push_back(5.0);\n    return res;\n}\n\nvector<pair<int,int>> generate_pairs(int N, int A, const array<int,11>& a) {\n    const double PI = acos(-1.0);\n    vector<double> lambdas = select_lambdas(N, a);\n    set<pair<int,int>> st;\n\n    auto add_pair = [&](int m1, int m2) {\n        if (m1 < 1 || m2 < 1) return;\n        if (m1 + m2 - 2 > 100) return;\n        st.insert({m1, m2});\n    };\n\n    for (double lam : lambdas) {\n        double P = 4.0 * N / (PI * lam); // target total grid cells in square coords\n        vector<double> ratios = {1.0, 1.4, 1.0 / 1.4};\n\n        for (double ratio : ratios) {\n            int base1 = max(1, (int)llround(sqrt(P * ratio)));\n            for (int d1 = -2; d1 <= 2; d1++) {\n                int m1 = max(1, base1 + d1);\n                int base2 = max(1, (int)llround(P / m1));\n                for (int d2 = -1; d2 <= 1; d2++) {\n                    int m2 = max(1, base2 + d2);\n                    add_pair(m1, m2);\n                }\n            }\n        }\n    }\n\n    // Add a few 1D-ish and generic fallbacks\n    vector<int> oneD = {2,3,4,5,6,8,10,15,20,30,40,50,60,80,100};\n    for (int m : oneD) {\n        add_pair(1, m);\n        add_pair(m, 1);\n    }\n\n    // Add around sqrt(4A/pi), i.e. \"number of useful pieces ~= attendees\"\n    {\n        const double PI2 = acos(-1.0);\n        double P = 4.0 * max(1, A) / PI2;\n        int b = max(1, (int)llround(sqrt(P)));\n        for (int d1 = -3; d1 <= 3; d1++) {\n            int m1 = max(1, b + d1);\n            int m2 = max(1, (int)llround(P / m1));\n            for (int d2 = -2; d2 <= 2; d2++) add_pair(m1, m2 + d2);\n        }\n    }\n\n    vector<pair<int,int>> res(st.begin(), st.end());\n\n    // Keep a moderate number of pairs\n    sort(res.begin(), res.end(), [&](auto &L, auto &Rr) {\n        long long pL = 1LL * L.first * L.second;\n        long long pR = 1LL * Rr.first * Rr.second;\n        return pL > pR;\n    });\n    if ((int)res.size() > 90) res.resize(90);\n\n    return res;\n}\n\nvoid try_update_best(\n    BestSol& best,\n    const vector<double>& s,\n    const vector<double>& t,\n    int dx, int dy,\n    int m1, int m2,\n    double f1, double f2,\n    const array<int,11>& a\n) {\n    EvalResult e = evaluate_grid(s, t, m1, m2, f1, f2, a);\n    if (betterScore(e.score, e.goodCells, best)) {\n        best.score = e.score;\n        best.goodCells = e.goodCells;\n        best.dx = dx;\n        best.dy = dy;\n        best.m1 = m1;\n        best.m2 = m2;\n        best.f1 = f1;\n        best.f2 = f2;\n    }\n}\n\nvector<double> unique_fractions(vector<double> v) {\n    for (double &x : v) {\n        x = max(0.02, min(0.98, x));\n    }\n    sort(v.begin(), v.end());\n    vector<double> res;\n    for (double x : v) {\n        if (res.empty() || fabs(res.back() - x) > 1e-9) res.push_back(x);\n    }\n    return res;\n}\n\nlong long adjust_constant(\n    long long target,\n    long long low,\n    long long high,\n    const unordered_set<long long>& forbidden\n) {\n    for (long long d = 0; ; d++) {\n        long long c1 = target - d;\n        if (c1 >= low && c1 <= high && !forbidden.count(c1)) return c1;\n        if (d == 0) continue;\n        long long c2 = target + d;\n        if (c2 >= low && c2 <= high && !forbidden.count(c2)) return c2;\n    }\n}\n\narray<long long,4> line_from_ABC(long long A, long long B, long long C) {\n    long long aa = llabs(A), bb = llabs(B);\n    long long x, y;\n    extgcd_pos(max(1LL, aa), max(1LL, bb), x, y);\n\n    // Fix for zero coefficient cases\n    if (aa == 0) { x = 0; y = 1; }\n    else if (bb == 0) { x = 1; y = 0; }\n\n    if (A < 0) x = -x;\n    if (B < 0) y = -y;\n\n    long long x0 = x * C;\n    long long y0 = y * C;\n\n    // Shift along the line to keep coordinates small\n    long double denom = (long double)A * A + (long double)B * B;\n    long double tt = ((long double)x0 * B - (long double)y0 * A) / denom;\n    long long t = llround(tt);\n\n    x0 -= B * t;\n    y0 += A * t;\n\n    long long x1 = x0;\n    long long y1 = y0;\n    long long x2 = x0 - B;\n    long long y2 = y0 + A;\n\n    return {x1, y1, x2, y2};\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 A = 0;\n    for (int d = 1; d <= 10; d++) A += a[d];\n\n    auto pairs = generate_pairs(N, A, a);\n    auto dirs = generate_dirs();\n\n    BestSol best;\n\n    // Coarse search\n    for (auto [dx, dy] : dirs) {\n        double len = hypot((double)dx, (double)dy);\n        vector<double> s(N), t(N);\n        for (int i = 0; i < N; i++) {\n            s[i] = ((double)(-dy) * pts[i].x + (double)dx * pts[i].y) / len;\n            t[i] = ((double)dx * pts[i].x + (double)dy * pts[i].y) / len;\n        }\n\n        for (auto [m1, m2] : pairs) {\n            vector<double> fs1 = (m1 == 1 ? vector<double>{0.5} : vector<double>{0.25, 0.5, 0.75});\n            vector<double> fs2 = (m2 == 1 ? vector<double>{0.5} : vector<double>{0.25, 0.5, 0.75});\n            for (double f1 : fs1) {\n                for (double f2 : fs2) {\n                    try_update_best(best, s, t, dx, dy, m1, m2, f1, f2, a);\n                }\n            }\n        }\n    }\n\n    // Local refinement around the best\n    {\n        const double PI = acos(-1.0);\n        double ang0 = atan2((double)best.dy, (double)best.dx);\n        set<pair<int,int>> nearDirsSet;\n        const int L2 = 223;\n\n        for (int dd = -3; dd <= 3; dd++) {\n            double ang = ang0 + dd * (PI / 180.0); // \u00b13 degrees\n            int dx = (int)llround(L2 * cos(ang));\n            int dy = (int)llround(L2 * sin(ang));\n            nearDirsSet.insert(normalize_dir(dx, dy));\n        }\n        nearDirsSet.insert({best.dx, best.dy});\n\n        vector<pair<int,int>> nearDirs(nearDirsSet.begin(), nearDirsSet.end());\n\n        for (auto [dx, dy] : nearDirs) {\n            double len = hypot((double)dx, (double)dy);\n            vector<double> s(N), t(N);\n            for (int i = 0; i < N; i++) {\n                s[i] = ((double)(-dy) * pts[i].x + (double)dx * pts[i].y) / len;\n                t[i] = ((double)dx * pts[i].x + (double)dy * pts[i].y) / len;\n            }\n\n            for (int m1 = max(1, best.m1 - 2); m1 <= min(101, best.m1 + 2); m1++) {\n                for (int m2 = max(1, best.m2 - 2); m2 <= min(101, best.m2 + 2); m2++) {\n                    if (m1 + m2 - 2 > 100) continue;\n\n                    vector<double> fs1, fs2;\n                    if (m1 == 1) fs1 = {0.5};\n                    else fs1 = unique_fractions({0.25, 0.5, 0.75, best.f1 - 0.15, best.f1 - 0.07, best.f1, best.f1 + 0.07, best.f1 + 0.15});\n                    if (m2 == 1) fs2 = {0.5};\n                    else fs2 = unique_fractions({0.25, 0.5, 0.75, best.f2 - 0.15, best.f2 - 0.07, best.f2, best.f2 + 0.07, best.f2 + 0.15});\n\n                    for (double f1 : fs1) {\n                        for (double f2 : fs2) {\n                            try_update_best(best, s, t, dx, dy, m1, m2, f1, f2, a);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Reconstruct lines\n    int dx = best.dx, dy = best.dy;\n    double len = hypot((double)dx, (double)dy);\n\n    // Forbidden projected coordinates to avoid cutting strawberry centers\n    unordered_set<long long> forb1, forb2;\n    forb1.reserve(N * 2 + 10);\n    forb2.reserve(N * 2 + 10);\n    for (auto &p : pts) {\n        long long v1 = 1LL * (-dy) * p.x + 1LL * dx * p.y; // normal (-dy, dx)\n        long long v2 = 1LL * dx * p.x + 1LL * dy * p.y;    // normal (dx, dy)\n        forb1.insert(v1);\n        forb2.insert(v2);\n    }\n\n    long long lim = (long long)floor(R * len - 1e-7);\n\n    vector<array<long long,4>> out;\n\n    // Family 1: lines parallel to (dx,dy), normal A=-dy, B=dx\n    {\n        int m1 = best.m1;\n        if (m1 >= 2) {\n            double w = 2.0 * R / m1;\n            vector<long long> C(m1 - 1);\n            for (int k = 0; k < m1 - 1; k++) {\n                double c = -R + best.f1 * w + k * w; // geometric signed distance in rotated coord\n                C[k] = llround(c * len);\n            }\n            sort(C.begin(), C.end());\n            vector<long long> CC;\n            for (int i = 0; i < (int)C.size(); i++) {\n                long long low = (i == 0 ? -lim + 1 : CC.back() + 1);\n                long long high = lim - 1;\n                long long c = adjust_constant(C[i], low, high, forb1);\n                CC.push_back(c);\n            }\n            for (long long c : CC) {\n                out.push_back(line_from_ABC(-dy, dx, c));\n            }\n        }\n    }\n\n    // Family 2: lines parallel to (-dy,dx), normal A=dx, B=dy\n    {\n        int m2 = best.m2;\n        if (m2 >= 2) {\n            double w = 2.0 * R / m2;\n            vector<long long> C(m2 - 1);\n            for (int k = 0; k < m2 - 1; k++) {\n                double c = -R + best.f2 * w + k * w;\n                C[k] = llround(c * len);\n            }\n            sort(C.begin(), C.end());\n            vector<long long> CC;\n            for (int i = 0; i < (int)C.size(); i++) {\n                long long low = (i == 0 ? -lim + 1 : CC.back() + 1);\n                long long high = lim - 1;\n                long long c = adjust_constant(C[i], low, high, forb2);\n                CC.push_back(c);\n            }\n            for (long long c : CC) {\n                out.push_back(line_from_ABC(dx, dy, c));\n            }\n        }\n    }\n\n    // Safety: limit to K\n    if ((int)out.size() > K) {\n        out.resize(K);\n    }\n\n    cout << out.size() << '\\n';\n    for (auto &ln : out) {\n        cout << ln[0] << ' ' << ln[1] << ' ' << ln[2] << ' ' << ln[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int INF_PERIM = 1e9;\n\nusing Op = array<int, 8>;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : 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    double next_double() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\nstruct Cand {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n    int gain;\n    int perim;\n    int area;\n    double eval;\n};\n\nstruct EvalParams {\n    double beta;\n    double gamma;\n    double adjBonus;\n    int topKeep;\n    int pickTop;\n    double bias;\n    int maxPerim;\n};\n\nstruct Strategy {\n    vector<int> caps;\n    double betaHi, betaLo;\n    double gammaHi, gammaLo;\n    double adjHi, adjLo;\n    int topKeep;\n    int pickTop;\n    double bias;\n};\n\nstruct State {\n    int N = 0;\n    int dotCount = 0;\n    uint8_t dot[MAXN][MAXN]{};\n    uint8_t H[MAXN][MAXN]{};   // (x,y) - (x+1,y)\n    uint8_t V[MAXN][MAXN]{};   // (x,y) - (x,y+1)\n    uint8_t D1[MAXN][MAXN]{};  // (x,y) - (x+1,y+1)\n    uint8_t D2[MAXN][MAXN]{};  // (x,y+1) - (x+1,y)\n    long long sumW = 0;\n    vector<Op> ops;\n};\n\nint N, M;\nint W[MAXN][MAXN];\nvector<int> cellOrder;\n\ninline int enc(int x, int y) { return (x << 6) | y; }\ninline int decx(int v) { return v >> 6; }\ninline int decy(int v) { return v & 63; }\ninline bool inside(int x, int y) { return 0 <= x && x < N && 0 <= y && y < N; }\ninline int sgn(int x) { return (x > 0) - (x < 0); }\n\nint eastA[MAXN][MAXN], westA[MAXN][MAXN], northA[MAXN][MAXN], southA[MAXN][MAXN];\nint neA[MAXN][MAXN], nwA[MAXN][MAXN], seA[MAXN][MAXN], swA[MAXN][MAXN];\n\ninline bool segment_used(const State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        int bx = min(x1, x2);\n        return st.H[bx][y1];\n    }\n    if (x1 == x2) {\n        int by = min(y1, y2);\n        return st.V[x1][by];\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D1[bx][by];\n    } else {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D2[bx][by];\n    }\n}\n\ninline void mark_segment(State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        int bx = min(x1, x2);\n        st.H[bx][y1] = 1;\n        return;\n    }\n    if (x1 == x2) {\n        int by = min(y1, y2);\n        st.V[x1][by] = 1;\n        return;\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        int bx = min(x1, x2), by = min(y1, y2);\n        st.D1[bx][by] = 1;\n    } else {\n        int bx = min(x1, x2), by = min(y1, y2);\n        st.D2[bx][by] = 1;\n    }\n}\n\ninline bool check_edge(const State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    if (len <= 0) return false;\n\n    int x = x1, y = y1;\n    for (int i = 1; i < len; i++) {\n        x += dx;\n        y += dy;\n        if (st.dot[x][y]) return false;\n    }\n\n    x = x1; y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        if (segment_used(st, x, y, nx, ny)) return false;\n        x = nx; y = ny;\n    }\n    return true;\n}\n\ninline void mark_edge(State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    int x = x1, y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        mark_segment(st, x, y, nx, ny);\n        x = nx;\n        y = ny;\n    }\n}\n\ninline bool valid_rect(const State& st, const Cand& c) {\n    if (st.dot[c.x1][c.y1]) return false;\n    if (!st.dot[c.x2][c.y2] || !st.dot[c.x3][c.y3] || !st.dot[c.x4][c.y4]) return false;\n\n    if (!check_edge(st, c.x1, c.y1, c.x2, c.y2)) return false;\n    if (!check_edge(st, c.x2, c.y2, c.x3, c.y3)) return false;\n    if (!check_edge(st, c.x3, c.y3, c.x4, c.y4)) return false;\n    if (!check_edge(st, c.x4, c.y4, c.x1, c.y1)) return false;\n    return true;\n}\n\ninline void apply_move(State& st, const Cand& c) {\n    st.dot[c.x1][c.y1] = 1;\n    st.dotCount++;\n    st.sumW += W[c.x1][c.y1];\n\n    mark_edge(st, c.x1, c.y1, c.x2, c.y2);\n    mark_edge(st, c.x2, c.y2, c.x3, c.y3);\n    mark_edge(st, c.x3, c.y3, c.x4, c.y4);\n    mark_edge(st, c.x4, c.y4, c.x1, c.y1);\n\n    st.ops.push_back({c.x1, c.y1, c.x2, c.y2, c.x3, c.y3, c.x4, c.y4});\n}\n\ninline void push_top(vector<Cand>& best, const Cand& c, int K) {\n    if ((int)best.size() < K) {\n        best.push_back(c);\n        int i = (int)best.size() - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    } else if (c.eval > best.back().eval) {\n        best.back() = c;\n        int i = K - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    }\n}\n\ninline int adjacent_count8(const State& st, int x, int y) {\n    int cnt = 0;\n    for (int dx = -1; dx <= 1; dx++) {\n        for (int dy = -1; dy <= 1; dy++) {\n            if (dx == 0 && dy == 0) continue;\n            int nx = x + dx, ny = y + dy;\n            if (inside(nx, ny) && st.dot[nx][ny]) cnt++;\n        }\n    }\n    return cnt;\n}\n\nvoid build_nearest(const State& st) {\n    for (int y = 0; y < N; y++) {\n        int last = -1;\n        for (int x = 0; x < N; x++) {\n            westA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int x = N - 1; x >= 0; x--) {\n            eastA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        int last = -1;\n        for (int y = 0; y < N; y++) {\n            southA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int y = N - 1; y >= 0; y--) {\n            northA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            swA[x][y] = (x == 0 || y == 0) ? -1\n                     : (st.dot[x - 1][y - 1] ? enc(x - 1, y - 1) : swA[x - 1][y - 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = N - 1; y >= 0; y--) {\n            neA[x][y] = (x == N - 1 || y == N - 1) ? -1\n                     : (st.dot[x + 1][y + 1] ? enc(x + 1, y + 1) : neA[x + 1][y + 1]);\n        }\n    }\n    for (int x = 0; x < N; x++) {\n        for (int y = N - 1; y >= 0; y--) {\n            nwA[x][y] = (x == 0 || y == N - 1) ? -1\n                     : (st.dot[x - 1][y + 1] ? enc(x - 1, y + 1) : nwA[x - 1][y + 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = 0; y < N; y++) {\n            seA[x][y] = (x == N - 1 || y == 0) ? -1\n                     : (st.dot[x + 1][y - 1] ? enc(x + 1, y - 1) : seA[x + 1][y - 1]);\n        }\n    }\n}\n\nvector<Cand> collect_top_candidates(const State& st, const EvalParams& prm) {\n    build_nearest(st);\n    vector<Cand> best;\n    best.reserve(prm.topKeep);\n\n    auto try_add = [&](int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {\n        if (!inside(x3, y3)) return;\n        if (!st.dot[x3][y3]) return;\n\n        int l1 = max(abs(x2 - x1), abs(y2 - y1));\n        int l2 = max(abs(x4 - x1), abs(y4 - y1));\n        if (l1 <= 0 || l2 <= 0) return;\n\n        Cand c;\n        c.x1 = x1; c.y1 = y1;\n        c.x2 = x2; c.y2 = y2;\n        c.x3 = x3; c.y3 = y3;\n        c.x4 = x4; c.y4 = y4;\n        c.gain = W[x1][y1];\n        c.perim = 2 * (l1 + l2);\n        c.area = l1 * l2;\n        if (c.perim > prm.maxPerim) return;\n\n        int adj = adjacent_count8(st, x1, y1);\n        c.eval = c.gain + prm.adjBonus * adj - prm.beta * c.perim - prm.gamma * c.area;\n\n        if (valid_rect(st, c)) push_top(best, c, prm.topKeep);\n    };\n\n    for (int id : cellOrder) {\n        int x = decx(id), y = decy(id);\n        if (st.dot[x][y]) continue;\n\n        int e = eastA[x][y], w = westA[x][y], n = northA[x][y], s = southA[x][y];\n        int ne = neA[x][y], nw = nwA[x][y], se = seA[x][y], sw = swA[x][y];\n\n        // Axis-aligned\n        if (e != -1 && n != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (e != -1 && s != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (w != -1 && n != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n        if (w != -1 && s != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4);\n        }\n\n        // 45-degree rectangles\n        if (ne != -1 && nw != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (ne != -1 && se != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (sw != -1 && nw != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n        if (sw != -1 && se != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4);\n        }\n    }\n\n    return best;\n}\n\nint choose_idx(const vector<Cand>& cand, int pickTop, double bias, XorShift64& rng) {\n    if (cand.empty()) return -1;\n    int m = min((int)cand.size(), pickTop);\n    if (m <= 1) return 0;\n    double r = rng.next_double();\n    int idx = (int)(pow(r, bias) * m);\n    if (idx >= m) idx = m - 1;\n    return idx;\n}\n\nState run_strategy(const State& initial, Strategy stg, XorShift64& rng,\n                   const function<double()>& elapsed, double TL) {\n    State st = initial;\n    st.ops.clear();\n    st.ops.reserve(N * N);\n\n    // Small random perturbation for diversity\n    auto pert = [&](double v, double lo, double hi) {\n        double mul = lo + (hi - lo) * rng.next_double();\n        return v * mul;\n    };\n    stg.betaHi = pert(stg.betaHi, 0.90, 1.10);\n    stg.betaLo = pert(stg.betaLo, 0.90, 1.10);\n    stg.gammaHi = pert(stg.gammaHi, 0.90, 1.10);\n    stg.gammaLo = pert(stg.gammaLo, 0.90, 1.10);\n    stg.adjHi = pert(stg.adjHi, 0.85, 1.15);\n    stg.adjLo = pert(stg.adjLo, 0.85, 1.15);\n    stg.bias = max(1.0, pert(stg.bias, 0.90, 1.10));\n    stg.pickTop = max(1, stg.pickTop + (int)(rng.next_u32() % 3) - 1);\n    stg.pickTop = min(stg.pickTop, stg.topKeep);\n\n    int stage = 0;\n    while (elapsed() < TL) {\n        if (stage >= (int)stg.caps.size()) stage = (int)stg.caps.size() - 1;\n        int cap = stg.caps[stage];\n\n        double prog = double(st.dotCount - M) / max(1, N * N - M);\n        EvalParams prm;\n        prm.beta = stg.betaHi * (1.0 - prog) + stg.betaLo * prog;\n        prm.gamma = stg.gammaHi * (1.0 - prog) + stg.gammaLo * prog;\n        prm.adjBonus = stg.adjHi * (1.0 - prog) + stg.adjLo * prog;\n        prm.topKeep = stg.topKeep;\n        prm.pickTop = stg.pickTop;\n        prm.bias = stg.bias;\n        prm.maxPerim = cap;\n\n        auto cand = collect_top_candidates(st, prm);\n        if (cand.empty()) {\n            if (stage + 1 < (int)stg.caps.size()) {\n                stage++;\n                continue;\n            } else {\n                break;\n            }\n        }\n\n        int idx = choose_idx(cand, prm.pickTop, prm.bias, rng);\n        apply_move(st, cand[idx]);\n    }\n    return st;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State initial;\n    initial.N = N;\n    initial.dotCount = 0;\n\n    vector<pair<int, int>> initPts;\n    initPts.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        initial.dot[x][y] = 1;\n        initial.dotCount++;\n        initPts.push_back({x, y});\n    }\n\n    int c = (N - 1) / 2;\n    cellOrder.clear();\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            W[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n            cellOrder.push_back(enc(x, y));\n        }\n    }\n\n    sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n        int xa = decx(a), ya = decy(a);\n        int xb = decx(b), yb = decy(b);\n        if (W[xa][ya] != W[xb][yb]) return W[xa][ya] > W[xb][yb];\n        if (xa != xb) return xa < xb;\n        return ya < yb;\n    });\n\n    initial.sumW = 0;\n    for (auto [x, y] : initPts) initial.sumW += W[x][y];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    for (auto [x, y] : initPts) {\n        seed ^= (uint64_t)(x * 131 + y * 10007 + 17) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n    XorShift64 rng(seed);\n\n    vector<Strategy> strategies = {\n        // Strong small-first infrastructure builder\n        {{8, 12, 16, 24, INF_PERIM}, 0.95, 0.12, 0.12, 0.010, 2.0, 0.2, 56, 4, 2.6},\n        {{10, 14, 20, INF_PERIM},    0.70, 0.08, 0.08, 0.008, 1.5, 0.1, 48, 4, 2.4},\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.20, 0.18, 0.18, 0.020, 2.6, 0.5, 64, 5, 2.9},\n\n        // Balanced\n        {{INF_PERIM}, 0.45, 0.03, 0.040, 0.002, 0.8, 0.0, 44, 3, 2.1},\n        {{INF_PERIM}, 0.25, 0.02, 0.020, 0.001, 0.4, 0.0, 40, 2, 1.8},\n\n        // More weight-oriented\n        {{18, 28, INF_PERIM}, 0.35, 0.01, 0.020, 0.000, 0.5, 0.0, 44, 2, 1.6},\n        {{INF_PERIM}, 0.12, 0.00, 0.005, 0.000, 0.2, 0.0, 36, 1, 1.0},\n    };\n\n    auto stTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - stTime).count();\n    };\n\n    const double TL = 4.75;\n\n    long long bestSum = initial.sumW;\n    vector<Op> bestOps;\n\n    // First, run one deterministic-ish strong strategy\n    {\n        Strategy first = strategies[0];\n        State st = run_strategy(initial, first, rng, elapsed, TL);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n    }\n\n    int turn = 0;\n    while (elapsed() < TL) {\n        Strategy stg = strategies[turn % strategies.size()];\n        State st = run_strategy(initial, stg, rng, elapsed, TL);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n        turn++;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto& op : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << op[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};\n\nstatic constexpr int N = 10;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\n// region ids\n// 0: TL, 1: TR, 2: BL, 3: BR, 4: BC\nstruct Board {\n    array<uint8_t, 100> a;\n    Board() { a.fill(0); }\n};\n\nstruct Solver {\n    array<int, 101> f{};\n    int total_cnt[4]{};\n    int rem_after[101][4]{}; // rem_after[t][c] = number of flavor c in turns t+1..100\n    Board board;\n\n    array<int, 4> target_region{}; // flavor 1..3 -> region id\n    int dist_table[5][100]{};\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver() {\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void init_dist() {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int idx = r * N + c;\n                dist_table[0][idx] = r + c;                         // TL\n                dist_table[1][idx] = r + (N - 1 - c);              // TR\n                dist_table[2][idx] = (N - 1 - r) + c;              // BL\n                dist_table[3][idx] = (N - 1 - r) + (N - 1 - c);    // BR\n                dist_table[4][idx] = (N - 1 - r) + min(abs(c - 4), abs(c - 5)); // BC\n            }\n        }\n    }\n\n    void read_input() {\n        uint64_t seed = 1469598103934665603ull;\n        for (int i = 1; i <= 100; i++) {\n            cin >> f[i];\n            total_cnt[f[i]]++;\n            seed ^= (uint64_t)(f[i] + 1009 * i);\n            seed *= 1099511628211ull;\n        }\n        rng = XorShift64(seed ^ 0x9e3779b97f4a7c15ull);\n        init_dist();\n\n        for (int c = 1; c <= 3; c++) rem_after[100][c] = 0;\n        for (int t = 99; t >= 0; t--) {\n            for (int c = 1; c <= 3; c++) rem_after[t][c] = rem_after[t + 1][c];\n            rem_after[t][f[t + 1]]++;\n        }\n    }\n\n    static inline void place(Board &b, int p, int flavor) {\n        int cnt = 0;\n        for (int i = 0; i < 100; i++) {\n            if (b.a[i] == 0) {\n                ++cnt;\n                if (cnt == p) {\n                    b.a[i] = (uint8_t)flavor;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline Board tilt(const Board &in, int dir) {\n        Board out;\n        if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                int wr = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr++ * N + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < N; c++) {\n                int wr = N - 1;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr-- * N + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = 0;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc++] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = N - 1;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc--] = v;\n                }\n            }\n        }\n        return out;\n    }\n\n    static inline int component_square_sum(const Board &b) {\n        bool vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; s++) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            int qh = 0, qt = 0;\n            q[qt++] = s;\n            vis[s] = true;\n            int sz = 0;\n\n            while (qh < qt) {\n                int v = q[qh++];\n                ++sz;\n                int r = v / N, c = v % N;\n\n                if (r > 0) {\n                    int nv = v - N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (r + 1 < N) {\n                    int nv = v + N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c + 1 < N) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    long long heuristic(const Board &b, int turn) const {\n        int rowcnt[10][4] = {};\n        int colcnt[10][4] = {};\n        int same_adj = 0, diff_adj = 0;\n        int dist_pen = 0;\n        int block_score = 0;\n\n        for (int idx = 0; idx < 100; idx++) {\n            uint8_t col = b.a[idx];\n            if (!col) continue;\n            int r = idx / N, c = idx % N;\n\n            rowcnt[r][col]++;\n            colcnt[c][col]++;\n\n            int mult = 1 + rem_after[turn][col] / 18;\n            dist_pen += dist_table[target_region[col]][idx] * mult;\n\n            if (c + 1 < N) {\n                uint8_t v = b.a[idx + 1];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t v = b.a[idx + N];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n        }\n\n        int purity = 0;\n        for (int i = 0; i < N; i++) {\n            for (int c = 1; c <= 3; c++) {\n                purity += rowcnt[i][c] * rowcnt[i][c];\n                purity += colcnt[i][c] * colcnt[i][c];\n            }\n        }\n\n        for (int r = 0; r + 1 < N; r++) {\n            for (int c = 0; c + 1 < N; c++) {\n                int cnt[4] = {};\n                uint8_t v1 = b.a[r * N + c];\n                uint8_t v2 = b.a[r * N + (c + 1)];\n                uint8_t v3 = b.a[(r + 1) * N + c];\n                uint8_t v4 = b.a[(r + 1) * N + (c + 1)];\n                if (v1) cnt[v1]++;\n                if (v2) cnt[v2]++;\n                if (v3) cnt[v3]++;\n                if (v4) cnt[v4]++;\n\n                int kinds = 0, occ = 0, sq = 0;\n                for (int col = 1; col <= 3; col++) {\n                    if (cnt[col]) {\n                        kinds++;\n                        occ += cnt[col];\n                        sq += cnt[col] * cnt[col];\n                    }\n                }\n                block_score += sq;\n                if (kinds >= 2) block_score -= 2 * occ * (kinds - 1);\n            }\n        }\n\n        int comp2 = component_square_sum(b);\n\n        int wComp = 28 + turn / 4;              // late game: stronger final-structure emphasis\n        int wSame = 16;\n        int wDiff = 13;\n        int wPurity = 2;\n        int wBlock = 5;\n        int wTarget = max(2, 19 - turn / 6);   // early game: stronger regional separation\n\n        long long val = 0;\n        val += 1LL * wComp * comp2;\n        val += 1LL * wSame * same_adj;\n        val -= 1LL * wDiff * diff_adj;\n        val += 1LL * wPurity * purity;\n        val += 1LL * wBlock * block_score;\n        val -= 1LL * wTarget * dist_pen;\n        return val;\n    }\n\n    long long value_after_tilt(const Board &b, int turn, int depth) {\n        if (turn == 100) {\n            return component_square_sum(b);\n        }\n        if (depth == 0) {\n            return heuristic(b, turn);\n        }\n\n        int empties = 100 - turn;\n        long long sum = 0;\n\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = value_after_tilt(nb, turn + 1, depth - 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n        return sum;\n    }\n\n    int choose_depth(int rem_future) const {\n        double t = elapsed();\n        if (t > 1.82) return 1;\n        if (rem_future <= 7 && t < 1.70) return 3;\n        if (rem_future <= 20 && t < 1.78) return 2;\n        return 1;\n    }\n\n    int greedy_dir_for_sim(const Board &b, int turn) {\n        long long best = LLONG_MIN;\n        int best_dir = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(b, dir);\n            long long v = heuristic(nb, turn);\n            if (v > best) {\n                best = v;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void choose_layout() {\n        vector<array<int, 3>> templates = {\n            {0, 1, 4}, // TL, TR, BC\n            {0, 1, 3}  // TL, TR, BR\n        };\n\n        const int TRIALS = 4;\n        int sampled_p[TRIALS][101]{};\n\n        for (int tr = 0; tr < TRIALS; tr++) {\n            for (int turn = 1; turn <= 100; turn++) {\n                int empties = 101 - turn;\n                sampled_p[tr][turn] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        long long best_total = -1;\n        array<int, 4> best_map = {0, 0, 1, 4};\n\n        array<int, 3> perm = {0, 1, 2};\n        for (auto tpl : templates) {\n            sort(perm.begin(), perm.end());\n            do {\n                array<int, 4> cand = {0, tpl[perm[0]], tpl[perm[1]], tpl[perm[2]]};\n                auto backup = target_region;\n                target_region = cand;\n\n                long long total = 0;\n                for (int tr = 0; tr < TRIALS; tr++) {\n                    Board b;\n                    for (int turn = 1; turn <= 100; turn++) {\n                        place(b, sampled_p[tr][turn], f[turn]);\n                        int dir = greedy_dir_for_sim(b, turn);\n                        b = tilt(b, dir);\n                    }\n                    total += component_square_sum(b);\n                }\n\n                target_region = backup;\n\n                if (total > best_total) {\n                    best_total = total;\n                    best_map = cand;\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n\n        target_region = best_map;\n    }\n\n    int decide_action(int turn) {\n        int rem_future = 100 - turn;\n        int depth = choose_depth(rem_future);\n\n        long long best = LLONG_MIN;\n        long long best_h = LLONG_MIN;\n        int best_dir = 0;\n\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(board, dir);\n            long long v = value_after_tilt(nb, turn, depth);\n            long long h = heuristic(nb, turn);\n            if (v > best || (v == best && h > best_h)) {\n                best = v;\n                best_h = h;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void solve() {\n        read_input();\n        choose_layout();\n\n        for (int turn = 1; turn <= 100; turn++) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place(board, p, f[turn]);\n            int dir = decide_action(turn);\n            board = tilt(board, dir);\n\n            cout << DIR_CH[dir] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ==================== Exact solver for eps = 0 ====================\n\nstruct ExactNoNoiseSolver {\n    int M, N, C;\n    vector<vector<int>> perm_maps;          // perm_maps[p][old_edge_idx] = new_edge_idx\n    vector<uint32_t> reps;                  // chosen canonical masks\n    unordered_map<uint32_t, int> id_of;     // canonical mask -> index\n\n    static int unlabeled_count(int n) {\n        if (n == 4) return 11;\n        if (n == 5) return 34;\n        if (n == 6) return 156;\n        return 0;\n    }\n\n    static vector<pair<int,int>> edge_list(int n) {\n        vector<pair<int,int>> e;\n        for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) e.push_back({i, j});\n        return e;\n    }\n\n    uint32_t permute_mask(uint32_t mask, const vector<int>& mp) const {\n        uint32_t res = 0;\n        while (mask) {\n            int b = __builtin_ctz(mask);\n            mask &= mask - 1;\n            res |= (1u << mp[b]);\n        }\n        return res;\n    }\n\n    uint32_t canonical(uint32_t mask) const {\n        uint32_t best = UINT32_MAX;\n        for (const auto& mp : perm_maps) {\n            uint32_t x = permute_mask(mask, mp);\n            if (x < best) best = x;\n        }\n        return best;\n    }\n\n    string mask_to_string(uint32_t mask) const {\n        string s;\n        s.reserve(C);\n        for (int i = 0; i < C; ++i) s.push_back(((mask >> i) & 1u) ? '1' : '0');\n        return s;\n    }\n\n    uint32_t string_to_mask(const string& s) const {\n        uint32_t mask = 0;\n        for (int i = 0; i < (int)s.size(); ++i) if (s[i] == '1') mask |= (1u << i);\n        return mask;\n    }\n\n    ExactNoNoiseSolver(int M_) : M(M_) {\n        if (M <= unlabeled_count(4)) N = 4;\n        else if (M <= unlabeled_count(5)) N = 5;\n        else N = 6;\n        C = N * (N - 1) / 2;\n\n        auto edges = edge_list(N);\n        vector<vector<int>> pos(N, vector<int>(N, -1));\n        for (int i = 0; i < C; ++i) {\n            auto [u, v] = edges[i];\n            pos[u][v] = pos[v][u] = i;\n        }\n\n        vector<int> p(N);\n        iota(p.begin(), p.end(), 0);\n        do {\n            vector<int> mp(C);\n            for (int i = 0; i < C; ++i) {\n                auto [u, v] = edges[i];\n                int a = p[u], b = p[v];\n                if (a > b) swap(a, b);\n                mp[i] = pos[a][b];\n            }\n            perm_maps.push_back(move(mp));\n        } while (next_permutation(p.begin(), p.end()));\n\n        set<uint32_t> seen;\n        uint32_t total = 1u << C;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            uint32_t can = canonical(mask);\n            if (seen.insert(can).second) reps.push_back(can);\n        }\n        sort(reps.begin(), reps.end());\n        reps.resize(M);\n        for (int i = 0; i < M; ++i) id_of[reps[i]] = i;\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (uint32_t m : reps) cout << mask_to_string(m) << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        uint32_t mask = string_to_mask(H);\n        uint32_t can = canonical(mask);\n        auto it = id_of.find(can);\n        if (it == id_of.end()) return 0;\n        return it->second;\n    }\n};\n\n// ==================== RNG ====================\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    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// ==================== General solver ====================\n\nstruct GeneralSolver {\n    struct Candidate {\n        uint16_t mask;\n        vector<uint8_t> seq; // sorted noiseless degree sequence\n    };\n\n    struct GraphCode {\n        uint16_t mask;\n        vector<uint8_t> seq;      // sorted noiseless degree sequence\n        vector<uint8_t> edgeBits; // upper triangle in lexicographic order\n        string gstr;\n    };\n\n    struct Design {\n        int N = -1, R = -1, mode = -1;\n        vector<int> sizes;\n        vector<Candidate> selected;\n        double quick = -1e100;\n        double valScore = -1e100;\n    };\n\n    int M;\n    double eps;\n    int N, R, C;\n    vector<int> sizes;\n    double a, c;\n\n    vector<int> eu, ev; // pair endpoints for chosen N\n\n    vector<GraphCode> codes;\n    int S; // samples per graph\n    vector<vector<uint8_t>> samples; // [M*S][N]\n    vector<vector<float>> expected;  // [M][N]\n\n    static vector<pair<int,int>> make_pairs(int N) {\n        vector<pair<int,int>> res;\n        for (int i = 0; i < N; ++i) for (int j = i + 1; j < N; ++j) res.push_back({i, j});\n        return res;\n    }\n\n    static vector<int> build_sizes(int N, int R, int mode) {\n        vector<double> w(R, 1.0);\n        if (mode == 0) {\n            for (int i = 0; i < R; ++i) w[i] = 1.0;\n        } else if (mode == 1) {\n            for (int i = 0; i < R; ++i) w[i] = double(i + 1);\n        } else if (mode == 2) {\n            for (int i = 0; i < R; ++i) w[i] = pow(1.4, i);\n        } else if (mode == 3) {\n            for (int i = 0; i < R; ++i) w[i] = pow(1.8, i);\n        } else if (mode == 4) {\n            for (int i = 0; i < R; ++i) w[i] = pow(1.4, R - 1 - i);\n        } else if (mode == 5) {\n            for (int i = 0; i < R; ++i) w[i] = pow(1.8, R - 1 - i);\n        }\n\n        vector<int> s(R, 1);\n        int rem = N - R;\n        double sumw = accumulate(w.begin(), w.end(), 0.0);\n\n        vector<pair<double,int>> frac;\n        int used = 0;\n        for (int i = 0; i < R; ++i) {\n            double x = rem * w[i] / sumw;\n            int add = (int)floor(x);\n            s[i] += add;\n            used += add;\n            frac.push_back({x - add, i});\n        }\n        sort(frac.begin(), frac.end(), greater<>());\n        for (int k = 0; k < rem - used; ++k) s[frac[k].second]++;\n\n        return s;\n    }\n\n    static vector<uint8_t> degree_seq_for_mask(uint16_t mask, const vector<int>& s) {\n        int R = (int)s.size();\n        vector<int> pref(R + 1, 0);\n        for (int i = 0; i < R; ++i) pref[i + 1] = pref[i] + s[i];\n\n        vector<int> dom_after(R + 1, 0);\n        for (int i = R - 1; i >= 0; --i) {\n            dom_after[i] = dom_after[i + 1] + (((mask >> i) & 1) ? s[i] : 0);\n        }\n\n        int N = pref[R];\n        vector<uint8_t> seq;\n        seq.reserve(N);\n        for (int i = 0; i < R; ++i) {\n            int deg;\n            if ((mask >> i) & 1) {\n                deg = pref[i] + (s[i] - 1) + dom_after[i + 1];\n            } else {\n                deg = dom_after[i + 1];\n            }\n            for (int k = 0; k < s[i]; ++k) seq.push_back((uint8_t)deg);\n        }\n        sort(seq.begin(), seq.end());\n        return seq;\n    }\n\n    static vector<Candidate> build_candidates(int M, const vector<int>& s) {\n        int R = (int)s.size();\n        map<vector<uint8_t>, uint16_t> uniq;\n        for (uint16_t mask = 0; mask < (1u << R); ++mask) {\n            auto seq = degree_seq_for_mask(mask, s);\n            if (!uniq.count(seq)) uniq.emplace(seq, mask);\n        }\n        if ((int)uniq.size() < M) return {};\n        vector<Candidate> cands;\n        cands.reserve(uniq.size());\n        for (auto& kv : uniq) cands.push_back({kv.second, kv.first});\n        return cands;\n    }\n\n    static int dist_l1(const vector<uint8_t>& a, const vector<uint8_t>& b) {\n        int s = 0;\n        int n = (int)a.size();\n        for (int i = 0; i < n; ++i) s += abs((int)a[i] - (int)b[i]);\n        return s;\n    }\n\n    static vector<vector<int>> build_dist_matrix(const vector<Candidate>& cands) {\n        int C = (int)cands.size();\n        vector<vector<int>> D(C, vector<int>(C, 0));\n        for (int i = 0; i < C; ++i) {\n            for (int j = i + 1; j < C; ++j) {\n                int d = dist_l1(cands[i].seq, cands[j].seq);\n                D[i][j] = D[j][i] = d;\n            }\n        }\n        return D;\n    }\n\n    static vector<int> greedy_select_indices(int M, const vector<vector<int>>& D, const vector<int>& starts) {\n        int C = (int)D.size();\n        vector<int> best_sel;\n        pair<int,double> best_metric = {-1, -1.0};\n\n        for (int st : starts) {\n            vector<char> used(C, 0);\n            vector<int> minD(C, INT_MAX), sel;\n            sel.reserve(M);\n\n            auto add_idx = [&](int x) {\n                used[x] = 1;\n                sel.push_back(x);\n                for (int i = 0; i < C; ++i) if (!used[i]) minD[i] = min(minD[i], D[x][i]);\n            };\n\n            add_idx(st);\n            while ((int)sel.size() < M) {\n                int best = -1, bestd = -1, bestsum = -1;\n                for (int i = 0; i < C; ++i) if (!used[i]) {\n                    int candd = minD[i];\n                    int sumd = 0;\n                    for (int x : sel) sumd += D[i][x];\n                    if (candd > bestd || (candd == bestd && sumd > bestsum)) {\n                        bestd = candd;\n                        bestsum = sumd;\n                        best = i;\n                    }\n                }\n                add_idx(best);\n            }\n\n            int minNN = INT_MAX;\n            double avgNN = 0;\n            for (int i = 0; i < M; ++i) {\n                int nn = INT_MAX;\n                for (int j = 0; j < M; ++j) if (i != j) nn = min(nn, D[sel[i]][sel[j]]);\n                minNN = min(minNN, nn);\n                avgNN += nn;\n            }\n            avgNN /= M;\n            pair<int,double> met = {minNN, avgNN};\n            if (met > best_metric) {\n                best_metric = met;\n                best_sel = sel;\n            }\n        }\n        return best_sel;\n    }\n\n    static vector<int> make_start_indices(const vector<Candidate>& cands) {\n        int C = (int)cands.size();\n        vector<pair<int,int>> ord;\n        ord.reserve(C);\n        for (int i = 0; i < C; ++i) {\n            int s = 0;\n            for (uint8_t x : cands[i].seq) s += x;\n            ord.push_back({s, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        vector<int> starts;\n        vector<int> pos = {0, C / 4, C / 2, (3 * C) / 4, C - 1};\n        for (int p : pos) starts.push_back(ord[p].second);\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n        return starts;\n    }\n\n    static vector<GraphCode> build_graph_codes(const vector<Candidate>& selected, const vector<int>& sizes) {\n        int R = (int)sizes.size();\n        int N = accumulate(sizes.begin(), sizes.end(), 0);\n        vector<int> blkOf(N);\n        int cur = 0;\n        for (int b = 0; b < R; ++b) {\n            for (int k = 0; k < sizes[b]; ++k) blkOf[cur++] = b;\n        }\n\n        vector<GraphCode> codes;\n        codes.reserve(selected.size());\n\n        vector<pair<int,int>> pairs = make_pairs(N);\n\n        for (const auto& cand : selected) {\n            vector<uint8_t> bits;\n            bits.reserve(pairs.size());\n            string g;\n            g.reserve(pairs.size());\n\n            for (auto [u, v] : pairs) {\n                int bu = blkOf[u], bv = blkOf[v];\n                bool e;\n                if (bu == bv) e = ((cand.mask >> bu) & 1);\n                else {\n                    if (bu > bv) swap(bu, bv);\n                    e = ((cand.mask >> bv) & 1); // later block dominating\n                }\n                bits.push_back((uint8_t)e);\n                g.push_back(e ? '1' : '0');\n            }\n            codes.push_back({cand.mask, cand.seq, move(bits), move(g)});\n        }\n        return codes;\n    }\n\n    static vector<uint8_t> sample_noisy_sorted_degrees(\n        int N,\n        const vector<int>& eu,\n        const vector<int>& ev,\n        const vector<uint8_t>& edgeBits,\n        uint32_t thr,\n        SplitMix64& rng\n    ) {\n        int deg[100];\n        for (int i = 0; i < N; ++i) deg[i] = 0;\n        int C = (int)edgeBits.size();\n\n        for (int idx = 0; idx < C; ++idx) {\n            bool b = edgeBits[idx];\n            if (rng.next_u32() < thr) b = !b;\n            if (b) {\n                ++deg[eu[idx]];\n                ++deg[ev[idx]];\n            }\n        }\n\n        vector<uint8_t> seq(N);\n        for (int i = 0; i < N; ++i) seq[i] = (uint8_t)deg[i];\n        sort(seq.begin(), seq.end());\n        return seq;\n    }\n\n    static double decode_cost(\n        const vector<uint8_t>& q,\n        int graphId,\n        int M,\n        int S,\n        int N,\n        const vector<vector<uint8_t>>& samples,\n        const vector<vector<float>>& expected\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n        for (int t = 0; t < S; ++t) {\n            const auto& s = samples[graphId * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)q[i] - (int)s[i]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        double ideal = 0.0;\n        for (int i = 0; i < N; ++i) ideal += fabs((double)q[i] - expected[graphId][i]);\n\n        return avgBest + 0.30 * ideal;\n    }\n\n    static double validate_design(\n        int M,\n        double eps,\n        const vector<GraphCode>& codes,\n        int S_train,\n        int T_val\n    ) {\n        int N = (int)codes[0].seq.size();\n        auto pairs = make_pairs(N);\n        vector<int> eu, ev;\n        eu.reserve(pairs.size());\n        ev.reserve(pairs.size());\n        for (auto [u, v] : pairs) { eu.push_back(u); ev.push_back(v); }\n\n        double a = 1.0 - 2.0 * eps;\n        double c = eps * (N - 1);\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n\n        vector<vector<uint8_t>> train(M * S_train);\n        vector<vector<float>> expected(M, vector<float>(N));\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) expected[g][i] = (float)(c + a * codes[g].seq[i]);\n        }\n\n        SplitMix64 rng(123456789ULL + (uint64_t)N * 1000 + M * 17 + (uint64_t)(eps * 1000 + 0.5));\n\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S_train; ++t) {\n                train[g * S_train + t] = sample_noisy_sorted_degrees(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n\n        int correct = 0, total = 0;\n        for (int trueg = 0; trueg < M; ++trueg) {\n            for (int tv = 0; tv < T_val; ++tv) {\n                auto q = sample_noisy_sorted_degrees(N, eu, ev, codes[trueg].edgeBits, thr, rng);\n\n                int bestId = 0;\n                double bestCost = 1e100;\n                for (int g = 0; g < M; ++g) {\n                    double cost = decode_cost(q, g, M, S_train, N, train, expected);\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestId = g;\n                    }\n                }\n                if (bestId == trueg) ++correct;\n                ++total;\n            }\n        }\n\n        double acc = (double)correct / total;\n        return log(1e-12 + acc) * 0.0 + (100.0 * log(0.9) * (1.0 - acc) - log((double)N));\n    }\n\n    GeneralSolver(int M_, double eps_) : M(M_), eps(eps_) {\n        Design best;\n\n        int minR = 0;\n        while ((1u << minR) < (unsigned)M) ++minR;\n        minR = max(minR, 4);\n\n        vector<int> Ns;\n        if (eps < 0.05) Ns = {36, 52, 68, 84, 100};\n        else if (eps < 0.15) Ns = {52, 68, 84, 100};\n        else if (eps < 0.30) Ns = {68, 84, 100};\n        else Ns = {84, 100};\n\n        vector<int> Rs = {minR};\n        if (minR + 1 <= 8) Rs.push_back(minR + 1);\n        if (eps < 0.08 && minR + 2 <= 8) Rs.push_back(minR + 2);\n\n        vector<int> modes = {0, 1, 2, 3, 4, 5};\n\n        vector<Design> pool;\n\n        for (int NN : Ns) {\n            for (int RR : Rs) {\n                if ((1u << RR) < (unsigned)M) continue;\n                for (int mode : modes) {\n                    auto s = build_sizes(NN, RR, mode);\n                    auto cands = build_candidates(M, s);\n                    if ((int)cands.size() < M) continue;\n\n                    auto D = build_dist_matrix(cands);\n                    auto starts = make_start_indices(cands);\n                    auto sel_idx = greedy_select_indices(M, D, starts);\n\n                    vector<Candidate> sel;\n                    sel.reserve(M);\n                    for (int idx : sel_idx) sel.push_back(cands[idx]);\n                    sort(sel.begin(), sel.end(), [](const Candidate& x, const Candidate& y) {\n                        return x.seq < y.seq;\n                    });\n\n                    int minNN = INT_MAX;\n                    double avgNN = 0.0;\n                    for (int i = 0; i < M; ++i) {\n                        int ii = sel_idx[i];\n                        int nn = INT_MAX;\n                        for (int j = 0; j < M; ++j) if (i != j) {\n                            int jj = sel_idx[j];\n                            nn = min(nn, D[ii][jj]);\n                        }\n                        minNN = min(minNN, nn);\n                        avgNN += nn;\n                    }\n                    avgNN /= M;\n\n                    Design d;\n                    d.N = NN;\n                    d.R = RR;\n                    d.mode = mode;\n                    d.sizes = move(s);\n                    d.selected = move(sel);\n\n                    double sigma = sqrt(max(1e-9, (NN - 1) * eps * (1.0 - eps)));\n                    d.quick = minNN + 0.2 * avgNN - 0.05 * sigma * NN;\n                    pool.push_back(move(d));\n                }\n            }\n        }\n\n        sort(pool.begin(), pool.end(), [](const Design& a, const Design& b) {\n            return a.quick > b.quick;\n        });\n\n        int checkTop = min<int>(6, pool.size());\n        for (int i = 0; i < checkTop; ++i) {\n            auto codesTry = build_graph_codes(pool[i].selected, pool[i].sizes);\n            int S_train = (eps < 0.15 ? 6 : (eps < 0.30 ? 8 : 10));\n            int T_val   = (eps < 0.15 ? 3 : 4);\n            pool[i].valScore = validate_design(M, eps, codesTry, S_train, T_val);\n        }\n\n        if (checkTop == 0) {\n            // Very conservative fallback\n            N = 100;\n            R = minR;\n            sizes = build_sizes(N, R, 3);\n            auto cands = build_candidates(M, sizes);\n            auto D = build_dist_matrix(cands);\n            auto starts = make_start_indices(cands);\n            auto sel_idx = greedy_select_indices(M, D, starts);\n            vector<Candidate> sel;\n            for (int idx : sel_idx) sel.push_back(cands[idx]);\n            sort(sel.begin(), sel.end(), [](const Candidate& x, const Candidate& y) {\n                return x.seq < y.seq;\n            });\n            codes = build_graph_codes(sel, sizes);\n        } else {\n            int besti = 0;\n            for (int i = 1; i < checkTop; ++i) {\n                if (pool[i].valScore > pool[besti].valScore) besti = i;\n            }\n            N = pool[besti].N;\n            R = pool[besti].R;\n            sizes = pool[besti].sizes;\n            codes = build_graph_codes(pool[besti].selected, sizes);\n        }\n\n        C = N * (N - 1) / 2;\n        a = 1.0 - 2.0 * eps;\n        c = eps * (N - 1);\n\n        auto pairs = make_pairs(N);\n        eu.reserve(C);\n        ev.reserve(C);\n        for (auto [u, v] : pairs) {\n            eu.push_back(u);\n            ev.push_back(v);\n        }\n\n        if (eps < 0.05) S = 10;\n        else if (eps < 0.15) S = 14;\n        else if (eps < 0.25) S = 18;\n        else S = 24;\n        if (M < 20) S += 4;\n        S = min(S, 28);\n\n        samples.assign(M * S, {});\n        expected.assign(M, vector<float>(N));\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) {\n                expected[g][i] = (float)(c + a * codes[g].seq[i]);\n            }\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x3141592653589793ULL + (uint64_t)N * 10007 + M * 911);\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S; ++t) {\n                samples[g * S + t] = sample_noisy_sorted_degrees(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (const auto& code : codes) cout << code.gstr << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        int deg[100];\n        for (int i = 0; i < N; ++i) deg[i] = 0;\n        int p = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                if (H[p++] == '1') {\n                    ++deg[i];\n                    ++deg[j];\n                }\n            }\n        }\n        vector<uint8_t> q(N);\n        for (int i = 0; i < N; ++i) q[i] = (uint8_t)deg[i];\n        sort(q.begin(), q.end());\n\n        int bestId = 0;\n        double bestCost = 1e100;\n        for (int g = 0; g < M; ++g) {\n            double cost = decode_cost(q, g, M, S, N, samples, expected);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestId = g;\n            }\n        }\n        return bestId;\n    }\n};\n\n// ==================== main ====================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    if (fabs(eps) < 1e-12) {\n        ExactNoNoiseSolver solver(M);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        GeneralSolver solver(M, eps);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\nstatic const int MAXD = 30;\n\nstruct Solver {\n    struct Edge {\n        int u, v;\n        ll w;\n        int cell = 0;\n        double usage = 0.0;\n        ll detour = 0;\n        double imp = 1.0;\n    };\n    struct Adj {\n        int to, id;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<pair<int,int>> coord;\n    vector<vector<Adj>> g;\n\n    // assignment\n    vector<int> dayOf;                 // edge -> day [0..D-1]\n    vector<int> posInDay;\n    vector<vector<int>> dayEdges;\n    vector<int> quota;\n    vector<int> dayCnt;\n    vector<double> dayLoad;            // sum of importance\n\n    // penalties\n    vector<array<int, MAXD>> cntV;     // vertex x day\n    vector<array<int, MAXD>> cntCell;  // cell x day\n    int G;                             // grid size\n    int C;                             // number of cells\n\n    // weights for proxy objective\n    double WA, WB, WC;\n\n    // landmarks / sampled evaluation\n    vector<int> landmarks;\n    int L_imp = 16;\n    int L_eval = 6;\n    vector<vector<ll>> origEvalDist;   // [L_eval][N]\n    vector<ll> dayScore;               // sampled true-ish score per day\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    Solver() {\n        rng.seed((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n        st = chrono::steady_clock::now();\n    }\n\n    inline double comb2(int x) const {\n        return 0.5 * x * (x - 1);\n    }\n\n    void read_input() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            ll w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i] = {u, v, w};\n            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n        }\n        coord.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> coord[i].first >> coord[i].second;\n        }\n\n        G = max(4, min(6, (int)llround(sqrt((double)D)) + 1));\n        C = G * G;\n\n        for (int i = 0; i < M; i++) {\n            double mx = (coord[edges[i].u].first + coord[edges[i].v].first) * 0.5;\n            double my = (coord[edges[i].u].second + coord[edges[i].v].second) * 0.5;\n            int cx = min(G - 1, max(0, (int)(mx * G / 1001.0)));\n            int cy = min(G - 1, max(0, (int)(my * G / 1001.0)));\n            edges[i].cell = cy * G + cx;\n        }\n\n        dayOf.assign(M, -1);\n        posInDay.assign(M, -1);\n        dayEdges.assign(D, {});\n        quota.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) quota[d]++;\n        dayCnt.assign(D, 0);\n        dayLoad.assign(D, 0.0);\n\n        cntV.assign(N, {});\n        for (auto &a : cntV) a.fill(0);\n        cntCell.assign(C, {});\n        for (auto &a : cntCell) a.fill(0);\n\n        // proxy weights\n        // day-load balance, same-vertex collision, same-cell collision\n        WA = 0.02;\n        WB = 4.0;\n        WC = 0.5;\n    }\n\n    // Dijkstra. If needParent=true, fill parV/parE with one shortest path tree.\n    void dijkstra_full(int src,\n                       vector<ll> &dist,\n                       int skipEdge = -1,\n                       int skipDay = -1,\n                       int target = -1,\n                       vector<int> *parV = nullptr,\n                       vector<int> *parE = nullptr) {\n        dist.assign(N, INF64);\n        if (parV) parV->assign(N, -1);\n        if (parE) parE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n            if (v == target) return;\n\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == skipEdge) continue;\n                if (skipDay >= 0 && dayOf[id] == skipDay) continue;\n\n                int to = ad.to;\n                ll nd = cd + edges[id].w;\n\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parV) (*parV)[to] = v;\n                    if (parE) (*parE)[to] = id;\n                    pq.push({nd, to});\n                } else if (parE && nd == dist[to]) {\n                    if ((*parE)[to] == -1 || id < (*parE)[to]) {\n                        (*parV)[to] = v;\n                        (*parE)[to] = id;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> choose_landmarks(int L) {\n        L = min(L, N);\n        vector<int> res;\n        res.reserve(L);\n\n        vector<ll> best(N, (1LL << 62));\n        int first = 0;\n        res.push_back(first);\n\n        auto dist2 = [&](int a, int b) -> ll {\n            ll dx = coord[a].first - coord[b].first;\n            ll dy = coord[a].second - coord[b].second;\n            return dx * dx + dy * dy;\n        };\n\n        for (int i = 0; i < N; i++) best[i] = dist2(i, first);\n\n        while ((int)res.size() < L) {\n            int cand = -1;\n            ll val = -1;\n            for (int i = 0; i < N; i++) {\n                if (best[i] > val) {\n                    val = best[i];\n                    cand = i;\n                }\n            }\n            res.push_back(cand);\n            for (int i = 0; i < N; i++) {\n                best[i] = min(best[i], dist2(i, cand));\n            }\n        }\n        return res;\n    }\n\n    void compute_importance() {\n        landmarks = choose_landmarks(L_imp);\n        L_imp = (int)landmarks.size();\n        L_eval = min(L_eval, L_imp);\n\n        origEvalDist.assign(L_eval, vector<ll>(N, INF64));\n\n        // usage from shortest path trees\n        vector<ll> dist;\n        vector<int> parV, parE;\n        for (int li = 0; li < L_imp; li++) {\n            int s = landmarks[li];\n            dijkstra_full(s, dist, -1, -1, -1, &parV, &parE);\n\n            if (li < L_eval) {\n                origEvalDist[li] = dist;\n            }\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sz(N, 1);\n            for (int v : ord) {\n                if (v == s) continue;\n                int pe = parE[v];\n                int pv = parV[v];\n                if (pe >= 0) {\n                    edges[pe].usage += sz[v];\n                    sz[pv] += sz[v];\n                }\n            }\n        }\n\n        // detour: distance between endpoints without that edge\n        vector<ll> dist2;\n        for (int eid = 0; eid < M; eid++) {\n            int s = edges[eid].u;\n            int t = edges[eid].v;\n            dijkstra_full(s, dist2, eid, -1, t, nullptr, nullptr);\n            ll alt = dist2[t];\n            if (alt >= INF64 / 2) alt = (ll)1e18; // should not happen in 2-edge-connected graph\n            edges[eid].detour = max<ll>(0, alt - edges[eid].w);\n        }\n\n        double avgUsage = 0.0;\n        double avgDet = 0.0;\n        for (int i = 0; i < M; i++) {\n            avgUsage += edges[i].usage + 1.0;\n            avgDet += (double)edges[i].detour + 1.0;\n        }\n        avgUsage /= M;\n        avgDet /= M;\n\n        double meanRaw = 0.0;\n        vector<double> raw(M);\n        for (int i = 0; i < M; i++) {\n            double u = (edges[i].usage + 1.0) / avgUsage;\n            double d = ((double)edges[i].detour + 1.0) / avgDet;\n            raw[i] = u * d;\n            meanRaw += raw[i];\n        }\n        meanRaw /= M;\n        if (meanRaw <= 0) meanRaw = 1.0;\n\n        for (int i = 0; i < M; i++) {\n            edges[i].imp = raw[i] / meanRaw;\n        }\n    }\n\n    inline double greedy_add_cost(int eid, int d) const {\n        const auto &e = edges[eid];\n        double x = e.imp;\n        double cost = 0.0;\n        cost += WA * (2.0 * dayLoad[d] * x + x * x);\n        cost += WB * (cntV[e.u][d] + cntV[e.v][d]);\n        cost += WC * (cntCell[e.cell][d]);\n        return cost;\n    }\n\n    void assign_initial(int eid, int d) {\n        dayOf[eid] = d;\n        posInDay[eid] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(eid);\n        dayCnt[d]++;\n        dayLoad[d] += edges[eid].imp;\n        cntV[edges[eid].u][d]++;\n        cntV[edges[eid].v][d]++;\n        cntCell[edges[eid].cell][d]++;\n    }\n\n    void build_initial_solution() {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (edges[a].imp != edges[b].imp) return edges[a].imp > edges[b].imp;\n            return a < b;\n        });\n\n        for (int eid : ord) {\n            double bestCost = 1e100;\n            int bestDay = -1;\n\n            vector<int> days(D);\n            iota(days.begin(), days.end(), 0);\n            shuffle(days.begin(), days.end(), rng);\n\n            for (int d : days) {\n                if (dayCnt[d] >= quota[d]) continue;\n                double c = greedy_add_cost(eid, d);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestDay = d;\n                }\n            }\n            if (bestDay == -1) {\n                for (int d = 0; d < D; d++) {\n                    if (dayCnt[d] < quota[d]) {\n                        bestDay = d;\n                        break;\n                    }\n                }\n            }\n            assign_initial(eid, bestDay);\n        }\n    }\n\n    void move_edge_day(int eid, int nd) {\n        int od = dayOf[eid];\n        if (od == nd) return;\n\n        // remove from old day vector\n        int pos = posInDay[eid];\n        int last = dayEdges[od].back();\n        dayEdges[od][pos] = last;\n        posInDay[last] = pos;\n        dayEdges[od].pop_back();\n\n        // add to new\n        posInDay[eid] = (int)dayEdges[nd].size();\n        dayEdges[nd].push_back(eid);\n\n        // counts\n        dayCnt[od]--;\n        dayCnt[nd]++;\n        dayLoad[od] -= edges[eid].imp;\n        dayLoad[nd] += edges[eid].imp;\n\n        cntV[edges[eid].u][od]--;\n        cntV[edges[eid].v][od]--;\n        cntV[edges[eid].u][nd]++;\n        cntV[edges[eid].v][nd]++;\n\n        cntCell[edges[eid].cell][od]--;\n        cntCell[edges[eid].cell][nd]++;\n\n        dayOf[eid] = nd;\n    }\n\n    void apply_swap(int e1, int e2) {\n        int d1 = dayOf[e1], d2 = dayOf[e2];\n        if (d1 == d2) return;\n        move_edge_day(e1, d2);\n        move_edge_day(e2, d1);\n    }\n\n    double proxy_swap_delta(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return 0.0;\n\n        const auto &E1 = edges[e1];\n        const auto &E2 = edges[e2];\n\n        double delta = 0.0;\n\n        // load term\n        {\n            double la = dayLoad[a], lb = dayLoad[b];\n            double x = E1.imp, y = E2.imp;\n            double nla = la - x + y;\n            double nlb = lb - y + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n\n        // vertex term\n        {\n            int vs[4] = {E1.u, E1.v, E2.u, E2.v};\n            sort(vs, vs + 4);\n            int m = unique(vs, vs + 4) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][a];\n                int cb = cntV[v][b];\n                int da = 0;\n                if (E1.u == v || E1.v == v) da--;\n                if (E2.u == v || E2.v == v) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WB * add;\n        }\n\n        // cell term\n        {\n            int cs[2] = {E1.cell, E2.cell};\n            sort(cs, cs + 2);\n            int m = unique(cs, cs + 2) - cs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int c = cs[i];\n                int ca = cntCell[c][a];\n                int cb = cntCell[c][b];\n                int da = 0;\n                if (E1.cell == c) da--;\n                if (E2.cell == c) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WC * add;\n        }\n\n        return delta;\n    }\n\n    int pick_edge_from_day(int d, bool highImp) {\n        const auto &vec = dayEdges[d];\n        int sz = (int)vec.size();\n        if (sz == 0) return -1;\n        int best = vec[rng() % sz];\n        for (int t = 0; t < 2; t++) {\n            int cand = vec[rng() % sz];\n            if (highImp) {\n                if (edges[cand].imp > edges[best].imp) best = cand;\n            } else {\n                if (edges[cand].imp < edges[best].imp) best = cand;\n            }\n        }\n        return best;\n    }\n\n    void proxy_local_search(double timeLimit) {\n        int it = 0;\n        while (elapsed() < timeLimit) {\n            it++;\n\n            int a = rng() % D;\n            int b = rng() % D;\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n            // make a somewhat heavier day donate an important edge\n            if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n\n            double delta = proxy_swap_delta(e1, e2);\n            if (delta < 0.0) {\n                apply_swap(e1, e2);\n            }\n        }\n    }\n\n    ll eval_day_score(int blockedDay) {\n        vector<ll> dist;\n        ll total = 0;\n        for (int si = 0; si < L_eval; si++) {\n            dijkstra_full(landmarks[si], dist, -1, blockedDay, -1, nullptr, nullptr);\n            for (int v = 0; v < N; v++) {\n                ll dv = (dist[v] >= INF64 / 2 ? (ll)1e9 : dist[v]);\n                total += dv - origEvalDist[si][v];\n            }\n        }\n        return total;\n    }\n\n    void sampled_local_search(double timeLimit) {\n        dayScore.assign(D, 0);\n        for (int d = 0; d < D; d++) dayScore[d] = eval_day_score(d);\n\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n\n        int evalCnt = 0;\n        const int MAX_EVAL = 400;\n\n        while (elapsed() < timeLimit && evalCnt < MAX_EVAL) {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dayScore[a] > dayScore[b];\n            });\n\n            int topk = min(4, D);\n            int botk = min(4, D);\n            int a = ord[rng() % topk];\n            int b = ord[D - 1 - (rng() % botk)];\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n\n            double pdelta = proxy_swap_delta(e1, e2);\n            if (pdelta > 2.0 && (rng() & 3)) continue;\n\n            ll oldScore = dayScore[a] + dayScore[b];\n\n            apply_swap(e1, e2);\n            ll na = eval_day_score(a);\n            ll nb = eval_day_score(b);\n            evalCnt++;\n\n            ll newScore = na + nb;\n            if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                dayScore[a] = na;\n                dayScore[b] = nb;\n            } else {\n                apply_swap(e1, e2); // revert\n            }\n        }\n    }\n\n    void solve() {\n        read_input();\n        compute_importance();\n        build_initial_solution();\n\n        // fast proxy improvement\n        if (elapsed() < 2.2) {\n            proxy_local_search(2.2);\n        }\n\n        // closer-to-true improvement with sampled Dijkstra\n        if (elapsed() < 5.6) {\n            sampled_local_search(5.6);\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << (dayOf[i] + 1);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    solver.output();\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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp(int nL = 0, int nR = 0) : nL(nL), nR(nR), g(nL) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        bool found = false;\n        for (int u = 0; u < nL; ++u) {\n            if (pairU[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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\nstruct ObjData {\n    int D;\n    vector<string> f, r;\n    vector<vector<int>> Xs, Ys;\n    vector<int> Xmask, Ymask;\n};\n\nstruct OccCandidate {\n    vector<char> occ;\n    int V = 0;\n    string name;\n};\n\nstruct AnalysisResult {\n    int V = 0;\n    vector<int> occLins;\n    vector<pair<int,int>> doms;\n};\n\nstruct Block {\n    int size;\n    vector<int> cells;\n};\n\nstruct Partition {\n    int V = 0;\n    string name;\n    vector<Block> blocks;\n    vector<vector<int>> bySize; // indices into blocks, by line length / size\n};\n\nstruct Solver {\n    int D;\n    ObjData obj[2];\n    Timer timer;\n\n    Solver(int D) : D(D) {}\n\n    int lin(int x, int y, int z) const {\n        return x * D * D + y * D + z;\n    }\n    tuple<int,int,int> invlin(int id) const {\n        int z = id % D;\n        id /= D;\n        int y = id % D;\n        int x = id / D;\n        return {x, y, z};\n    }\n    int lin2(int x, int y) const {\n        return x * D + y;\n    }\n\n    void prepare_obj(int idx, const vector<string>& f, const vector<string>& r) {\n        obj[idx].D = D;\n        obj[idx].f = f;\n        obj[idx].r = r;\n        obj[idx].Xs.assign(D, {});\n        obj[idx].Ys.assign(D, {});\n        obj[idx].Xmask.assign(D, 0);\n        obj[idx].Ymask.assign(D, 0);\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) if (f[z][x] == '1') {\n                obj[idx].Xs[z].push_back(x);\n                obj[idx].Xmask[z] |= (1 << x);\n            }\n            for (int y = 0; y < D; ++y) if (r[z][y] == '1') {\n                obj[idx].Ys[z].push_back(y);\n                obj[idx].Ymask[z] |= (1 << y);\n            }\n        }\n    }\n\n    static int popcnt(int x) {\n        return __builtin_popcount((unsigned)x);\n    }\n\n    AnalysisResult analyze_occ_for_domino(const vector<char>& occ) const {\n        AnalysisResult res;\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\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 = lin(x, y, z);\n            if (!occ[id]) continue;\n            res.occLins.push_back(id);\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n        hk.max_matching();\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) {\n                res.doms.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n            }\n        }\n        res.V = (int)res.occLins.size();\n        return res;\n    }\n\n    // ---------------- cross construction ----------------\n\n    vector<char> build_cross_occ(const ObjData& o, const vector<pair<int,int>>& centers) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            int cx = centers[z].first;\n            int cy = centers[z].second;\n            for (int x : o.Xs[z]) occ[lin(x, cy, z)] = 1;\n            for (int y : o.Ys[z]) occ[lin(cx, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    int cross_transition_score(const ObjData& o, int z, pair<int,int> a, pair<int,int> b) const {\n        int xcap = popcnt(o.Xmask[z] & o.Xmask[z+1]);\n        int ycap = popcnt(o.Ymask[z] & o.Ymask[z+1]);\n        int s = 0;\n        if (a.second == b.second) s += xcap;\n        if (a.first  == b.first ) s += ycap;\n        if (a.first == b.first && a.second == b.second) s -= 1;\n        return s;\n    }\n\n    vector<pair<int,int>> init_cross_centers_dp(const ObjData& o) const {\n        vector<vector<pair<int,int>>> states(D);\n        for (int z = 0; z < D; ++z) {\n            for (int x : o.Xs[z]) for (int y : o.Ys[z]) states[z].push_back({x, y});\n        }\n        vector<vector<int>> dp(D), prv(D);\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1e9);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int cand = dp[z-1][i] + cross_transition_score(o, z-1, states[z-1][i], states[z][j]);\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        int best = 0;\n        for (int i = 1; i < (int)states[D-1].size(); ++i) {\n            if (dp[D-1][i] > dp[D-1][best]) best = i;\n        }\n        vector<pair<int,int>> centers(D);\n        int cur = best;\n        for (int z = D - 1; z >= 0; --z) {\n            centers[z] = states[z][cur];\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n        return centers;\n    }\n\n    int local_overlap_score(const ObjData& o, const vector<pair<int,int>>& centers, int z, pair<int,int> cand) const {\n        int s = 0;\n        if (z > 0) s += cross_transition_score(o, z - 1, centers[z - 1], cand);\n        if (z + 1 < D) s += cross_transition_score(o, z, cand, centers[z + 1]);\n        return s;\n    }\n\n    OccCandidate build_cross_optimized(const ObjData& o, const string& name) const {\n        vector<pair<int,int>> centers = init_cross_centers_dp(o);\n        auto bestOcc = build_cross_occ(o, centers);\n        auto bestAna = analyze_occ_for_domino(bestOcc);\n\n        bool improved = true;\n        for (int pass = 0; pass < 2 && improved; ++pass) {\n            improved = false;\n            for (int z = 0; z < D; ++z) {\n                auto curCenter = centers[z];\n                int curMatch = (int)bestAna.doms.size();\n                int curTie = local_overlap_score(o, centers, z, curCenter);\n\n                auto bestCenter = curCenter;\n                auto bestOccHere = bestOcc;\n                auto bestAnaHere = bestAna;\n                int bestMatch = curMatch;\n                int bestTie = curTie;\n\n                for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                    pair<int,int> cand = {x, y};\n                    if (cand == curCenter) continue;\n                    centers[z] = cand;\n                    auto occ = build_cross_occ(o, centers);\n                    auto ana = analyze_occ_for_domino(occ);\n                    int m = (int)ana.doms.size();\n                    int tie = local_overlap_score(o, centers, z, cand);\n                    if (m > bestMatch || (m == bestMatch && tie > bestTie)) {\n                        bestMatch = m;\n                        bestTie = tie;\n                        bestCenter = cand;\n                        bestOccHere = move(occ);\n                        bestAnaHere = move(ana);\n                    }\n                }\n\n                centers[z] = bestCenter;\n                if (bestCenter != curCenter) {\n                    bestOcc = move(bestOccHere);\n                    bestAna = move(bestAnaHere);\n                    if (bestMatch > curMatch) improved = true;\n                }\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(bestOcc);\n        ret.V = bestAna.V;\n        ret.name = name;\n        return ret;\n    }\n\n    OccCandidate build_cross_dp_only(const ObjData& o, const string& name) const {\n        auto centers = init_cross_centers_dp(o);\n        OccCandidate ret;\n        ret.occ = build_cross_occ(o, centers);\n        ret.V = count(ret.occ.begin(), ret.occ.end(), 1);\n        ret.name = name;\n        return ret;\n    }\n\n    // ---------------- simple minimal constructions ----------------\n\n    vector<char> build_min_occ(const ObjData& o, bool rev) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            auto X = o.Xs[z];\n            auto Y = o.Ys[z];\n            int a = (int)X.size();\n            int b = (int)Y.size();\n\n            if (a >= b) {\n                if (rev) reverse(Y.begin(), Y.end());\n                for (int j = 0; j < b; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = b; j < a; ++j) occ[lin(X[j], Y[0], z)] = 1;\n            } else {\n                if (rev) reverse(X.begin(), X.end());\n                for (int j = 0; j < a; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = a; j < b; ++j) occ[lin(X[0], Y[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    // ---------------- star-minimal construction ----------------\n\n    struct LayerState {\n        vector<int> cells2; // x*D+y sorted\n    };\n\n    vector<int> build_star_layer_cells(const ObjData& o, int z, bool anchorOnY, int anchorVal, int mode) const {\n        vector<int> res;\n        auto X = o.Xs[z];\n        auto Y = o.Ys[z];\n        sort(X.begin(), X.end());\n        sort(Y.begin(), Y.end());\n\n        if (anchorOnY) {\n            // a >= b, anchor y\n            int y0 = anchorVal;\n            vector<int> otherY;\n            for (int y : Y) if (y != y0) otherY.push_back(y);\n            if (mode & 1) reverse(otherY.begin(), otherY.end());\n\n            int k = (int)otherY.size();\n            vector<int> specialX;\n            if ((mode & 2) == 0) {\n                for (int i = 0; i < k; ++i) specialX.push_back(X[i]);\n            } else {\n                for (int i = 0; i < k; ++i) specialX.push_back(X[(int)X.size() - k + i]);\n            }\n\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) mp[specialX[i]] = otherY[i];\n            for (int x : X) {\n                auto it = mp.find(x);\n                if (it == mp.end()) res.push_back(lin2(x, y0));\n                else res.push_back(lin2(x, it->second));\n            }\n        } else {\n            // b > a, anchor x\n            int x0 = anchorVal;\n            vector<int> otherX;\n            for (int x : X) if (x != x0) otherX.push_back(x);\n            if (mode & 1) reverse(otherX.begin(), otherX.end());\n\n            int k = (int)otherX.size();\n            vector<int> specialY;\n            if ((mode & 2) == 0) {\n                for (int i = 0; i < k; ++i) specialY.push_back(Y[i]);\n            } else {\n                for (int i = 0; i < k; ++i) specialY.push_back(Y[(int)Y.size() - k + i]);\n            }\n\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) mp[specialY[i]] = otherX[i];\n            for (int y : Y) {\n                auto it = mp.find(y);\n                if (it == mp.end()) res.push_back(lin2(x0, y));\n                else res.push_back(lin2(it->second, y));\n            }\n        }\n\n        sort(res.begin(), res.end());\n        res.erase(unique(res.begin(), res.end()), res.end());\n        return res;\n    }\n\n    int overlap2d(const vector<int>& a, const vector<int>& b) const {\n        int i = 0, j = 0, cnt = 0;\n        while (i < (int)a.size() && j < (int)b.size()) {\n            if (a[i] == b[j]) { ++cnt; ++i; ++j; }\n            else if (a[i] < b[j]) ++i;\n            else ++j;\n        }\n        return cnt;\n    }\n\n    OccCandidate build_star_optimized(const ObjData& o, const string& name) const {\n        vector<vector<LayerState>> states(D);\n\n        for (int z = 0; z < D; ++z) {\n            unordered_set<string> seen;\n            int a = (int)o.Xs[z].size();\n            int b = (int)o.Ys[z].size();\n\n            if (a >= b) {\n                for (int y0 : o.Ys[z]) {\n                    for (int mode = 0; mode < 4; ++mode) {\n                        auto cells = build_star_layer_cells(o, z, true, y0, mode);\n                        string key;\n                        key.reserve(cells.size() * 3);\n                        for (int v : cells) {\n                            key += char(v / 256);\n                            key += char(v % 256);\n                            key += '#';\n                        }\n                        if (seen.insert(key).second) states[z].push_back({cells});\n                    }\n                }\n            } else {\n                for (int x0 : o.Xs[z]) {\n                    for (int mode = 0; mode < 4; ++mode) {\n                        auto cells = build_star_layer_cells(o, z, false, x0, mode);\n                        string key;\n                        key.reserve(cells.size() * 3);\n                        for (int v : cells) {\n                            key += char(v / 256);\n                            key += char(v % 256);\n                            key += '#';\n                        }\n                        if (seen.insert(key).second) states[z].push_back({cells});\n                    }\n                }\n            }\n        }\n\n        vector<vector<int>> dp(D), prv(D);\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1e9);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int sc = overlap2d(states[z-1][i].cells2, states[z][j].cells2);\n                    int cand = dp[z-1][i] + sc;\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n\n        int best = 0;\n        for (int i = 1; i < (int)states[D-1].size(); ++i) {\n            if (dp[D-1][i] > dp[D-1][best]) best = i;\n        }\n\n        vector<int> choice(D);\n        int cur = best;\n        for (int z = D - 1; z >= 0; --z) {\n            choice[z] = cur;\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : states[z][choice[z]].cells2) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(occ);\n        ret.V = count(ret.occ.begin(), ret.occ.end(), 1);\n        ret.name = name;\n        return ret;\n    }\n\n    // ---------------- occupancy candidate generation ----------------\n\n    vector<OccCandidate> build_occ_candidates(const ObjData& o) const {\n        vector<OccCandidate> cands;\n\n        auto add_occ = [&](OccCandidate c) {\n            for (auto& e : cands) {\n                if (e.occ == c.occ) return;\n            }\n            cands.push_back(move(c));\n        };\n\n        add_occ(build_cross_optimized(o, \"cross_local\"));\n        add_occ(build_cross_dp_only(o, \"cross_dp\"));\n\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, false);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minA\";\n            add_occ(move(c));\n        }\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, true);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minB\";\n            add_occ(move(c));\n        }\n\n        add_occ(build_star_optimized(o, \"star\"));\n\n        return cands;\n    }\n\n    // ---------------- partition into line blocks ----------------\n\n    bool cell_used(const vector<char>& unused, int x, int y, int z) const {\n        if (x < 0 || x >= D || y < 0 || y >= D || z < 0 || z >= D) return false;\n        return unused[lin(x, y, z)];\n    }\n\n    bool find_best_segment(const vector<char>& unused, int L, vector<int>& outCells) const {\n        const int dxs[3] = {1, 0, 0};\n        const int dys[3] = {0, 1, 0};\n        const int dzs[3] = {0, 0, 1};\n\n        bool found = false;\n        int bestExt = 1e9, bestPerp = 1e9, bestKey = 1e9;\n        vector<int> bestCells;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (!unused[lin(x, y, z)]) continue;\n            for (int dir = 0; dir < 3; ++dir) {\n                int dx = dxs[dir], dy = dys[dir], dz = dzs[dir];\n                int ex = x + (L - 1) * dx;\n                int ey = y + (L - 1) * dy;\n                int ez = z + (L - 1) * dz;\n                if (ex < 0 || ex >= D || ey < 0 || ey >= D || ez < 0 || ez >= D) continue;\n\n                vector<int> cells;\n                bool ok = true;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    int id = lin(nx, ny, nz);\n                    if (!unused[id]) { ok = false; break; }\n                    cells.push_back(id);\n                }\n                if (!ok) continue;\n\n                int ext = 0;\n                if (cell_used(unused, x - dx, y - dy, z - dz)) ++ext;\n                if (cell_used(unused, ex + dx, ey + dy, ez + dz)) ++ext;\n\n                int perp = 0;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    if (dir != 0) {\n                        perp += cell_used(unused, nx - 1, ny, nz);\n                        perp += cell_used(unused, nx + 1, ny, nz);\n                    }\n                    if (dir != 1) {\n                        perp += cell_used(unused, nx, ny - 1, nz);\n                        perp += cell_used(unused, nx, ny + 1, nz);\n                    }\n                    if (dir != 2) {\n                        perp += cell_used(unused, nx, ny, nz - 1);\n                        perp += cell_used(unused, nx, ny, nz + 1);\n                    }\n                }\n\n                int key = ((dir * D + x) * D + y) * D + z;\n                if (!found || ext < bestExt || (ext == bestExt && perp < bestPerp) ||\n                    (ext == bestExt && perp == bestPerp && key < bestKey)) {\n                    found = true;\n                    bestExt = ext;\n                    bestPerp = perp;\n                    bestKey = key;\n                    bestCells = move(cells);\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(bestCells);\n        return true;\n    }\n\n    vector<pair<int,int>> maximum_domino_pairs(const vector<char>& unused) const {\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\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 = lin(x, y, z);\n            if (!unused[id]) continue;\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n        vector<pair<int,int>> ret;\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) ret.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n        }\n        return ret;\n    }\n\n    Partition build_partition_lines(const OccCandidate& occCand, const vector<int>& order, const string& name) const {\n        Partition p;\n        p.V = occCand.V;\n        p.name = occCand.name + \":\" + name;\n        p.bySize.assign(D + 1, {});\n\n        vector<char> unused = occCand.occ;\n\n        for (int L : order) {\n            if (L < 3 || L > D) continue;\n            while (true) {\n                vector<int> seg;\n                if (!find_best_segment(unused, L, seg)) break;\n                for (int id : seg) unused[id] = 0;\n                int idx = (int)p.blocks.size();\n                p.blocks.push_back({L, seg});\n                p.bySize[L].push_back(idx);\n            }\n        }\n\n        auto doms = maximum_domino_pairs(unused);\n        vector<char> used2(D * D * D, 0);\n        for (auto [a, b] : doms) {\n            if (!unused[a] || !unused[b] || used2[a] || used2[b]) continue;\n            used2[a] = used2[b] = 1;\n            int idx = (int)p.blocks.size();\n            p.blocks.push_back({2, {a, b}});\n            p.bySize[2].push_back(idx);\n        }\n        for (int i = 0; i < D * D * D; ++i) {\n            if (used2[i]) unused[i] = 0;\n        }\n\n        for (int i = 0; i < D * D * D; ++i) {\n            if (unused[i]) {\n                int idx = (int)p.blocks.size();\n                p.blocks.push_back({1, {i}});\n                p.bySize[1].push_back(idx);\n            }\n        }\n\n        return p;\n    }\n\n    vector<Partition> build_partitions(const vector<OccCandidate>& occs) const {\n        vector<vector<int>> patterns;\n        auto add_pat = [&](vector<int> v) {\n            vector<int> w;\n            for (int x : v) if (3 <= x && x <= D) w.push_back(x);\n            if (w.empty()) w.clear();\n            for (auto& p : patterns) if (p == w) return;\n            patterns.push_back(w);\n        };\n\n        vector<int> desc;\n        for (int L = min(D, 8); L >= 3; --L) desc.push_back(L);\n        add_pat(desc);\n        add_pat({5,4,3});\n        add_pat({4,3});\n        add_pat({3});\n        add_pat({}); // domino only\n\n        vector<Partition> ret;\n        for (auto& occ : occs) {\n            for (auto& pat : patterns) {\n                string name;\n                if (pat.empty()) name = \"dom\";\n                else {\n                    name = \"L\";\n                    for (int x : pat) name += \"_\" + to_string(x);\n                }\n                ret.push_back(build_partition_lines(occ, pat, name));\n            }\n        }\n        return ret;\n    }\n\n    // ---------------- scoring and output ----------------\n\n    long double eval_pair(const Partition& A, const Partition& B) const {\n        long double score = (long double)A.V + (long double)B.V;\n        for (int s = 1; s <= D; ++s) {\n            int k = min((int)A.bySize[s].size(), (int)B.bySize[s].size());\n            score -= (long double)2 * s * k;\n            score += (long double)k / (long double)s;\n        }\n        return score;\n    }\n\n    pair<vector<int>, vector<int>> build_output_arrays(const Partition& A, const Partition& B) const {\n        vector<int> outA(D * D * D, 0), outB(D * D * D, 0);\n        int id = 1;\n\n        for (int s = D; s >= 1; --s) {\n            int k = min((int)A.bySize[s].size(), (int)B.bySize[s].size());\n            for (int i = 0; i < k; ++i) {\n                const auto& ba = A.blocks[A.bySize[s][i]];\n                const auto& bb = B.blocks[B.bySize[s][i]];\n                for (int c : ba.cells) outA[c] = id;\n                for (int c : bb.cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        for (int s = D; s >= 1; --s) {\n            int k = min((int)A.bySize[s].size(), (int)B.bySize[s].size());\n            for (int i = k; i < (int)A.bySize[s].size(); ++i) {\n                const auto& ba = A.blocks[A.bySize[s][i]];\n                for (int c : ba.cells) outA[c] = id;\n                ++id;\n            }\n            for (int i = k; i < (int)B.bySize[s].size(); ++i) {\n                const auto& bb = B.blocks[B.bySize[s][i]];\n                for (int c : bb.cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        return {outA, outB};\n    }\n\n    void solve() {\n        auto occ1 = build_occ_candidates(obj[0]);\n        auto occ2 = build_occ_candidates(obj[1]);\n\n        auto part1 = build_partitions(occ1);\n        auto part2 = build_partitions(occ2);\n\n        int bi = 0, bj = 0;\n        long double best = 1e100L;\n\n        for (int i = 0; i < (int)part1.size(); ++i) {\n            for (int j = 0; j < (int)part2.size(); ++j) {\n                long double sc = eval_pair(part1[i], part2[j]);\n                if (sc < best) {\n                    best = sc;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        auto [out1, out2] = build_output_arrays(part1[bi], part2[bj]);\n\n        int n = 0;\n        for (int v : out1) n = max(n, v);\n        for (int v : out2) n = max(n, v);\n\n        cout << n << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out1[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out2[i];\n        }\n        cout << '\\n';\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> f1(D), r1(D), f2(D), r2(D);\n    for (int i = 0; i < D; ++i) cin >> f1[i];\n    for (int i = 0; i < D; ++i) cin >> r1[i];\n    for (int i = 0; i < D; ++i) cin >> f2[i];\n    for (int i = 0; i < D; ++i) cin >> r2[i];\n\n    Solver solver(D);\n    solver.prepare_obj(0, f1, r1);\n    solver.prepare_obj(1, f2, r2);\n    solver.solve();\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }\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;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Tree {\n    vector<char> edgeOn;\n    vector<char> vertexOn;\n};\n\nstruct Solution {\n    vector<int> P;\n    vector<char> B;\n    long long S = (1LL << 62);\n    bool feasible = false;\n    double factor = 0.0;\n};\n\nstatic const long long INF64 = (1LL << 60);\nstatic const int MAX_EXACT_TERMINALS = 11;\n\nint N, M, K;\nvector<int> X, Y;\nvector<Edge> edges;\nvector<int> A, Bp;\nvector<vector<pair<int,int>>> g; // (to, edge_id)\n\nvector<vector<long long>> distSP;\nvector<vector<int>> parentV, parentE;\n\n// reqPow[v][k] = minimum integer power needed for vertex v to cover resident k.\n// 5001 means impossible due to P<=5000.\nvector<vector<unsigned short>> reqPow;\nvector<vector<pair<int,int>>> coverList;\n\nchrono::steady_clock::time_point g_start;\ndouble TIME_LIMIT = 1.85;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nint ceil_sqrt_ll(long long x) {\n    long long r = 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\nvoid compute_all_pairs_shortest_paths() {\n    distSP.assign(N, vector<long long>(N, INF64));\n    parentV.assign(N, vector<int>(N, -1));\n    parentE.assign(N, vector<int>(N, -1));\n\n    for (int s = 0; s < N; ++s) {\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        distSP[s][s] = 0;\n        parentV[s][s] = s;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != distSP[s][v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < distSP[s][to]) {\n                    distSP[s][to] = nd;\n                    parentV[s][to] = v;\n                    parentE[s][to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n}\n\nvoid preprocess_cover_info() {\n    reqPow.assign(N, vector<unsigned short>(K, 5001));\n    coverList.assign(N, {});\n\n    for (int v = 0; v < N; ++v) {\n        coverList[v].reserve(K);\n        for (int k = 0; k < K; ++k) {\n            long long dx = 1LL * X[v] - A[k];\n            long long dy = 1LL * Y[v] - Bp[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            if (p <= 5000) {\n                reqPow[v][k] = (unsigned short)p;\n                coverList[v].push_back({p, k});\n            }\n        }\n        sort(coverList[v].begin(), coverList[v].end());\n    }\n}\n\nlong long calc_cost(const vector<int>& P, const vector<char>& Eon) {\n    long long s = 0;\n    for (int i = 0; i < N; ++i) s += 1LL * P[i] * P[i];\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nbool verify_solution(const vector<int>& P, const vector<char>& Eon) {\n    vector<char> vis(N, 0);\n    queue<int> q;\n    vis[0] = 1;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (auto [to, eid] : g[v]) {\n            if (!Eon[eid]) continue;\n            if (!vis[to]) {\n                vis[to] = 1;\n                q.push(to);\n            }\n        }\n    }\n\n    for (int k = 0; k < K; ++k) {\n        bool ok = false;\n        for (int v = 0; v < N; ++v) {\n            if (!vis[v]) continue;\n            if (P[v] > 0 && reqPow[v][k] <= P[v]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nvoid add_path_from_source(int s, int t, vector<char>& inTree, vector<char>& edgeOn, vector<int>& newVertices) {\n    int cur = t;\n    while (cur != s) {\n        int pe = parentE[s][cur];\n        int pv = parentV[s][cur];\n        if (pe < 0 || pv < 0) break;\n        if (!edgeOn[pe]) edgeOn[pe] = 1;\n        if (!inTree[cur]) {\n            inTree[cur] = 1;\n            newVertices.push_back(cur);\n        }\n        if (!inTree[pv]) {\n            inTree[pv] = 1;\n            newVertices.push_back(pv);\n        }\n        cur = pv;\n    }\n}\n\nvector<int> get_terminals_from_P(const vector<int>& P, vector<char>& isTerminal) {\n    isTerminal.assign(N, 0);\n    vector<int> terminals;\n    terminals.push_back(0);\n    isTerminal[0] = 1;\n    for (int i = 0; i < N; ++i) {\n        if (i != 0 && P[i] > 0) {\n            terminals.push_back(i);\n            isTerminal[i] = 1;\n        } else if (i == 0 && P[i] > 0) {\n            isTerminal[i] = 1;\n        }\n    }\n    return terminals;\n}\n\nTree finalize_tree_from_selected(const vector<char>& sel0, const vector<char>& isTerminal) {\n    vector<char> sel = sel0;\n    vector<vector<int>> inc(N);\n    vector<int> deg(N, 0);\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        int u = edges[e].u, v = edges[e].v;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n        deg[u]++;\n        deg[v]++;\n    }\n\n    queue<int> q;\n    for (int v = 0; v < N; ++v) {\n        if (!isTerminal[v] && deg[v] == 1) q.push(v);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (isTerminal[v] || deg[v] != 1) continue;\n        int remE = -1;\n        for (int e : inc[v]) if (sel[e]) {\n            remE = e;\n            break;\n        }\n        if (remE == -1) continue;\n        sel[remE] = 0;\n        deg[v]--;\n        int to = edges[remE].u ^ edges[remE].v ^ v;\n        deg[to]--;\n        if (!isTerminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    Tree tr;\n    tr.edgeOn = sel;\n    tr.vertexOn.assign(N, 0);\n    tr.vertexOn[0] = 1;\n    for (int i = 0; i < N; ++i) if (isTerminal[i]) tr.vertexOn[i] = 1;\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        tr.vertexOn[edges[e].u] = 1;\n        tr.vertexOn[edges[e].v] = 1;\n    }\n    return tr;\n}\n\nTree build_heuristic_tree_from_terminals(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    int T = (int)terminals.size();\n\n    if (T >= 2) {\n        vector<long long> best(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> used(T, 0);\n        best[0] = 0;\n\n        for (int it = 0; it < T; ++it) {\n            int v = -1;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                int s = terminals[par[v]];\n                int t = terminals[v];\n                int cur = t;\n                while (cur != s) {\n                    int pe = parentE[s][cur];\n                    int pv = parentV[s][cur];\n                    if (pe < 0 || pv < 0) break;\n                    unionOn[pe] = 1;\n                    cur = pv;\n                }\n            }\n\n            for (int to = 0; to < T; ++to) {\n                if (used[to]) continue;\n                long long d = distSP[terminals[v]][terminals[to]];\n                if (d < best[to]) {\n                    best[to] = d;\n                    par[to] = v;\n                }\n            }\n        }\n    }\n\n    vector<int> ids;\n    for (int e = 0; e < M; ++e) if (unionOn[e]) ids.push_back(e);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return edges[a].w < edges[b].w;\n    });\n\n    vector<char> sel(M, 0);\n    DSU dsu(N);\n    for (int e : ids) {\n        if (dsu.merge(edges[e].u, edges[e].v)) sel[e] = 1;\n    }\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_exact_tree_from_terminals(const vector<int>& terminals, const vector<char>& isTerminal) {\n    int T = (int)terminals.size();\n    int SZ = 1 << T;\n\n    auto idx = [&](int mask, int v) { return mask * N + v; };\n\n    vector<long long> dp(SZ * N, INF64);\n    vector<int> kind(SZ * N, -3); // -3 unreachable, -2 path, -1 singleton source, >=0 split mask\n    vector<short> pv(SZ * N, -1);\n    vector<short> pe(SZ * N, -1);\n\n    for (int i = 0; i < T; ++i) {\n        int id = idx(1 << i, terminals[i]);\n        dp[id] = 0;\n        kind[id] = -1;\n    }\n\n    for (int mask = 1; mask < SZ; ++mask) {\n        if ((mask & (mask - 1)) != 0) {\n            for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n                int oth = mask ^ sub;\n                if (sub > oth) continue;\n                for (int v = 0; v < N; ++v) {\n                    long long a = dp[idx(sub, v)];\n                    long long b = dp[idx(oth, v)];\n                    if (a == INF64 || b == INF64) continue;\n                    long long nv = a + b;\n                    int idm = idx(mask, v);\n                    if (nv < dp[idm]) {\n                        dp[idm] = nv;\n                        kind[idm] = sub;\n                        pv[idm] = -1;\n                        pe[idm] = -1;\n                    }\n                }\n            }\n        }\n\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int v = 0; v < N; ++v) {\n            long long d = dp[idx(mask, v)];\n            if (d < INF64) pq.push({d, v});\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dp[idx(mask, v)]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                int idto = idx(mask, to);\n                if (nd < dp[idto]) {\n                    dp[idto] = nd;\n                    kind[idto] = -2;\n                    pv[idto] = (short)v;\n                    pe[idto] = (short)eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n\n    int full = SZ - 1;\n    int bestV = 0;\n    for (int v = 1; v < N; ++v) {\n        if (dp[idx(full, v)] < dp[idx(full, bestV)]) bestV = v;\n    }\n\n    vector<char> sel(M, 0);\n\n    function<void(int,int)> rec = [&](int mask, int v) {\n        int idm = idx(mask, v);\n        int k = kind[idm];\n        if (k == -3) return;\n        if (k == -2) {\n            int e = pe[idm];\n            int pvv = pv[idm];\n            if (e >= 0) sel[e] = 1;\n            if (pvv >= 0) rec(mask, pvv);\n        } else if (k == -1) {\n            return;\n        } else {\n            rec(k, v);\n            rec(mask ^ k, v);\n        }\n    };\n    rec(full, bestV);\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_best_tree_from_terminals(const vector<int>& P) {\n    vector<char> isTerminal;\n    vector<int> terminals = get_terminals_from_P(P, isTerminal);\n    if ((int)terminals.size() <= MAX_EXACT_TERMINALS) {\n        return build_exact_tree_from_terminals(terminals, isTerminal);\n    } else {\n        return build_heuristic_tree_from_terminals(terminals, isTerminal);\n    }\n}\n\nvector<int> vertices_from_tree(const Tree& tr) {\n    vector<int> vs;\n    for (int i = 0; i < N; ++i) if (tr.vertexOn[i]) vs.push_back(i);\n    return vs;\n}\n\nvoid shrink_exclusive(vector<int>& P, const vector<int>& allowed) {\n    while (true) {\n        vector<int> cnt(K, 0);\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= pv) cnt[k]++;\n            }\n        }\n\n        bool changed = false;\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int oldP = P[v];\n            int need = 0;\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= oldP && cnt[k] == 1) {\n                    need = max(need, (int)reqPow[v][k]);\n                }\n            }\n            if (need < oldP) {\n                for (int k = 0; k < K; ++k) {\n                    if (reqPow[v][k] <= oldP && reqPow[v][k] > need) {\n                        cnt[k]--;\n                    }\n                }\n                P[v] = need;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// Greedy repair / cover on a fixed allowed-vertex set, starting from current P.\nvector<int> greedy_cover_extend(const vector<int>& allowed, vector<int> P) {\n    vector<char> ok(N, 0);\n    for (int v : allowed) ok[v] = 1;\n    for (int i = 0; i < N; ++i) if (!ok[i]) P[i] = 0;\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    for (int v : allowed) {\n        if (P[v] <= 0) continue;\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : allowed) {\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) break;\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    shrink_exclusive(P, allowed);\n    return P;\n}\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> treeVertex;\n    vector<char> treeEdge;\n};\n\nInitialState initial_connected_greedy(double connFactor) {\n    vector<int> P(N, 0);\n    vector<char> inTree(N, 0), edgeOn(M, 0);\n    inTree[0] = 1;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v = 0; v < N; ++v) {\n            long double conn = inTree[v] ? 0.0L : (long double)connFactor * bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K; ++k) if (!covered[k]) {\n                for (int v = 0; v < N; ++v) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inTree[v] ? 0.0L : (long double)connFactor * bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n                if (bestV != -1) break;\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inTree[bestV]) {\n            vector<int> newVertices;\n            add_path_from_source(bestFrom[bestV], bestV, inTree, edgeOn, newVertices);\n            if (newVertices.empty()) {\n                inTree[bestV] = 1;\n                newVertices.push_back(bestV);\n            }\n            for (int nv : newVertices) {\n                for (int t = 0; t < N; ++t) {\n                    if (distSP[nv][t] < bestDist[t]) {\n                        bestDist[t] = distSP[nv][t];\n                        bestFrom[t] = nv;\n                    }\n                }\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    return {P, inTree, edgeOn};\n}\n\nvector<int> local_improve_by_turning_off(vector<int> P) {\n    for (int round = 0; round < 2; ++round) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n\n        Tree tr = build_best_tree_from_terminals(P);\n        vector<int> allowed = vertices_from_tree(tr);\n\n        vector<int> initP(N, 0);\n        for (int v : allowed) initP[v] = P[v];\n        P = greedy_cover_extend(allowed, initP);\n\n        tr = build_best_tree_from_terminals(P);\n        long long curCost = calc_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> cand;\n        for (int i = 0; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            if ((deg[a] == 1) != (deg[b] == 1)) return deg[a] == 1;\n            return sa > sb;\n        });\n\n        bool improved = false;\n        for (int v : cand) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n\n            vector<int> P2 = P;\n            P2[v] = 0;\n\n            vector<int> initP2(N, 0);\n            for (int u : allowed) initP2[u] = P2[u];\n            P2 = greedy_cover_extend(allowed, initP2);\n\n            Tree tr2 = build_best_tree_from_terminals(P2);\n            vector<int> allowed2 = vertices_from_tree(tr2);\n\n            vector<int> initP3(N, 0);\n            for (int u : allowed2) initP3[u] = P2[u];\n            P2 = greedy_cover_extend(allowed2, initP3);\n\n            tr2 = build_best_tree_from_terminals(P2);\n            long long cost2 = calc_cost(P2, tr2.edgeOn);\n\n            if (cost2 < curCost && verify_solution(P2, tr2.edgeOn)) {\n                P.swap(P2);\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n    return P;\n}\n\nSolution solve_attempt(double connFactor) {\n    Solution sol;\n    sol.factor = connFactor;\n\n    InitialState init = initial_connected_greedy(connFactor);\n\n    vector<int> allowed;\n    for (int i = 0; i < N; ++i) if (init.treeVertex[i]) allowed.push_back(i);\n\n    vector<int> P0(N, 0);\n    for (int v : allowed) P0[v] = init.P[v];\n    vector<int> P = greedy_cover_extend(allowed, P0);\n\n    for (int it = 0; it < 3; ++it) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n        Tree tr = build_best_tree_from_terminals(P);\n        allowed = vertices_from_tree(tr);\n        vector<int> initP(N, 0);\n        for (int v : allowed) initP[v] = P[v];\n        P = greedy_cover_extend(allowed, initP);\n    }\n\n    if (elapsed_sec() <= TIME_LIMIT) {\n        P = local_improve_by_turning_off(P);\n    }\n\n    Tree finalTree = build_best_tree_from_terminals(P);\n    allowed = vertices_from_tree(finalTree);\n    vector<int> initP(N, 0);\n    for (int v : allowed) initP[v] = P[v];\n    P = greedy_cover_extend(allowed, initP);\n    finalTree = build_best_tree_from_terminals(P);\n\n    sol.P = P;\n    sol.B = finalTree.edgeOn;\n    sol.S = calc_cost(sol.P, sol.B);\n    sol.feasible = verify_solution(sol.P, sol.B);\n    if (!sol.feasible) sol.S = (1LL << 62);\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M >> K;\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; ++i) cin >> X[i] >> Y[i];\n\n    edges.resize(M);\n    g.assign(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, v, w};\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    A.resize(K);\n    Bp.resize(K);\n    for (int i = 0; i < K; ++i) cin >> A[i] >> Bp[i];\n\n    compute_all_pairs_shortest_paths();\n    preprocess_cover_info();\n\n    vector<double> factors = {0.0, 0.45, 0.8, 1.2, 1.8, 2.8};\n    Solution best;\n\n    for (double f : factors) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n        Solution cur = solve_attempt(f);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    if (!best.feasible) {\n        best = solve_attempt(1.0);\n    }\n\n    // Final extra refinement on the current best if time remains.\n    if (best.feasible && elapsed_sec() <= TIME_LIMIT) {\n        vector<int> P = local_improve_by_turning_off(best.P);\n        Tree tr = build_best_tree_from_terminals(P);\n        vector<int> allowed = vertices_from_tree(tr);\n        vector<int> initP(N, 0);\n        for (int v : allowed) initP[v] = P[v];\n        P = greedy_cover_extend(allowed, initP);\n        tr = build_best_tree_from_terminals(P);\n\n        long long S = calc_cost(P, tr.edgeOn);\n        if (verify_solution(P, tr.edgeOn) && S < best.S) {\n            best.P = P;\n            best.B = tr.edgeOn;\n            best.S = S;\n            best.feasible = true;\n        }\n    }\n\n    if (!best.feasible) {\n        // Conservative fallback\n        vector<int> all(N);\n        iota(all.begin(), all.end(), 0);\n        vector<int> P = greedy_cover_extend(all, vector<int>(N, 0));\n        Tree tr = build_best_tree_from_terminals(P);\n        best.P = P;\n        best.B = tr.edgeOn;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (int)best.B[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Board {\n    uint16_t a[N][N];\n};\n\nstruct Plan {\n    vector<int> order;\n    int cost = 0;\n};\n\nstatic inline long long path_weight(int row, int val) {\n    // Prefer pushing larger values downward, and prefer doing so higher in the pyramid.\n    return 1000LL * (N - row) + val;\n}\n\n// Bring the minimum in T(tx, ty) to (tx, ty).\n// Returns the number of swaps used.\n// If ops != nullptr, records the actual swaps.\nstatic int apply_move(Board& b, int tx, int ty, vector<Op>* ops = nullptr) {\n    int bi = tx, bj = ty;\n    int best = b.a[tx][ty];\n\n    // Find the minimum in the descendant triangle.\n    for (int i = tx; i < N; ++i) {\n        int l = ty;\n        int r = ty + (i - tx);\n        for (int j = l; j <= r; ++j) {\n            if ((int)b.a[i][j] < best) {\n                best = b.a[i][j];\n                bi = i;\n                bj = j;\n            }\n        }\n    }\n\n    if (bi == tx && bj == ty) return 0;\n\n    // Among all shortest upward paths, choose one that tends to push larger values downward,\n    // especially near the top.\n    static long long memo[N][N];\n    static int vis[N][N];\n    static pair<short, short> parent_[N][N];\n    static int token = 1;\n    ++token;\n\n    auto dfs = [&](auto&& self, int i, int j) -> long long {\n        if (i == tx && j == ty) return 0;\n        if (vis[i][j] == token) return memo[i][j];\n        vis[i][j] = token;\n\n        long long best_score = LLONG_MIN / 4;\n        pair<short, short> best_parent = {-1, -1};\n\n        int d = i - tx;\n        int k = j - ty;\n\n        // Parent: (i-1, j-1)\n        if (k > 0) {\n            int pi = i - 1, pj = j - 1;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score ||\n                (cand == best_score && b.a[pi][pj] > b.a[best_parent.first][best_parent.second])) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n\n        // Parent: (i-1, j)\n        if (k < d) {\n            int pi = i - 1, pj = j;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score ||\n                (cand == best_score && b.a[pi][pj] > b.a[best_parent.first][best_parent.second])) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n\n        parent_[i][j] = best_parent;\n        memo[i][j] = best_score;\n        return best_score;\n    };\n\n    dfs(dfs, bi, bj);\n\n    int cnt = 0;\n    int i = bi, j = bj;\n    while (!(i == tx && j == ty)) {\n        auto [pi, pj] = parent_[i][j];\n        swap(b.a[i][j], b.a[pi][pj]);\n        if (ops) ops->push_back({i, j, pi, pj});\n        i = pi;\n        j = pj;\n        ++cnt;\n    }\n    return cnt;\n}\n\nstatic int apply_order(Board& b, int x, const vector<int>& order, vector<Op>* ops = nullptr) {\n    int cost = 0;\n    for (int y : order) cost += apply_move(b, x, y, ops);\n    return cost;\n}\n\nstatic vector<int> make_lr_order(int m, bool rev) {\n    vector<int> ord;\n    ord.reserve(m);\n    if (!rev) {\n        for (int y = 0; y < m; ++y) ord.push_back(y);\n    } else {\n        for (int y = m - 1; y >= 0; --y) ord.push_back(y);\n    }\n    return ord;\n}\n\nstatic Plan greedy_row_plan(const Board& start, int x) {\n    int m = x + 1;\n    Board cur = start;\n    uint32_t mask = 0;\n    vector<int> ord;\n    ord.reserve(m);\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        int best_y = -1;\n        int best_add = INT_MAX;\n        Board best_board{};\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n            if (add < best_add) {\n                best_add = add;\n                best_y = y;\n                best_board = tmp;\n            }\n        }\n\n        ord.push_back(best_y);\n        total += best_add;\n        mask |= (1u << best_y);\n        cur = best_board;\n    }\n\n    return {ord, total};\n}\n\nstruct Node {\n    Board b;\n    uint32_t mask;\n    int cost;\n    int parent;\n    int choice;\n};\n\nstatic int beam_width_for_row(int x) {\n    int m = x + 1;\n    if (m <= 6)  return 200;\n    if (m <= 10) return 100;\n    if (m <= 14) return 50;\n    if (m <= 20) return 28;\n    return 18;\n}\n\nstatic Plan beam_row_plan(const Board& start, int x) {\n    int m = x + 1;\n    if (m == 1) return {{0}, 0};\n\n    int W = beam_width_for_row(x);\n\n    vector<vector<Node>> levels(m + 1);\n    levels[0].push_back(Node{start, 0u, 0, -1, -1});\n\n    auto cmp = [](const Node& A, const Node& B) {\n        if (A.cost != B.cost) return A.cost < B.cost;\n        return A.mask < B.mask;\n    };\n\n    for (int depth = 0; depth < m; ++depth) {\n        vector<Node> cand;\n        cand.reserve(levels[depth].size() * (m - depth));\n\n        for (int idx = 0; idx < (int)levels[depth].size(); ++idx) {\n            const Node& cur = levels[depth][idx];\n            for (int y = 0; y < m; ++y) {\n                if (cur.mask & (1u << y)) continue;\n                Node nxt;\n                nxt.b = cur.b;\n                int add = apply_move(nxt.b, x, y, nullptr);\n                nxt.mask = cur.mask | (1u << y);\n                nxt.cost = cur.cost + add;\n                nxt.parent = idx;\n                nxt.choice = y;\n                cand.push_back(std::move(nxt));\n            }\n        }\n\n        if ((int)cand.size() > W) {\n            nth_element(cand.begin(), cand.begin() + W, cand.end(), cmp);\n            cand.resize(W);\n        }\n        sort(cand.begin(), cand.end(), cmp);\n        levels[depth + 1] = std::move(cand);\n    }\n\n    int best_idx = 0;\n    for (int i = 1; i < (int)levels[m].size(); ++i) {\n        if (levels[m][i].cost < levels[m][best_idx].cost) best_idx = i;\n    }\n\n    vector<int> order(m);\n    int idx = best_idx;\n    for (int depth = m; depth >= 1; --depth) {\n        order[depth - 1] = levels[depth][idx].choice;\n        idx = levels[depth][idx].parent;\n    }\n\n    return {order, levels[m][best_idx].cost};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board board{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v;\n            cin >> v;\n            board.a[x][y] = (uint16_t)v;\n        }\n    }\n\n    vector<Op> answer;\n    answer.reserve(6000);\n\n    // Bottom row does not need to satisfy any condition.\n    for (int x = 0; x < N - 1; ++x) {\n        vector<Plan> candidates;\n\n        // Beam-searched order.\n        candidates.push_back(beam_row_plan(board, x));\n\n        // Greedy order.\n        candidates.push_back(greedy_row_plan(board, x));\n\n        // Simple baselines.\n        {\n            auto ord = make_lr_order(x + 1, false);\n            Board tmp = board;\n            int c = apply_order(tmp, x, ord, nullptr);\n            candidates.push_back({ord, c});\n        }\n        {\n            auto ord = make_lr_order(x + 1, true);\n            Board tmp = board;\n            int c = apply_order(tmp, x, ord, nullptr);\n            candidates.push_back({ord, c});\n        }\n\n        int best_idx = 0;\n        for (int i = 1; i < (int)candidates.size(); ++i) {\n            if (candidates[i].cost < candidates[best_idx].cost) best_idx = i;\n        }\n\n        apply_order(board, x, candidates[best_idx].order, &answer);\n    }\n\n    cout << answer.size() << '\\n';\n    for (const auto& op : answer) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int D, N, M, mid, entrance;\n    array<char, 81> obstacle{};\n    array<char, 81> occupied{};\n    vector<vector<int>> nbrs;\n    vector<int> free_ids;\n    vector<int> label_at;\n    vector<char> used;\n    int current_empty_count; // includes entrance\n\n    Solver(int D_, int N_) : D(D_), N(N_) {\n        mid = (D - 1) / 2;\n        entrance = mid; // (0, mid)\n        nbrs.assign(D * D, {});\n        label_at.assign(D * D, -1);\n        build_neighbors();\n    }\n\n    inline int id(int i, int j) const { return i * D + j; }\n    inline int row(int v) const { return v / D; }\n    inline int col(int v) const { return v % D; }\n\n    void build_neighbors() {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int v = id(i, j);\n                if (i > 0) nbrs[v].push_back(id(i - 1, j));\n                if (i + 1 < D) nbrs[v].push_back(id(i + 1, j));\n                if (j > 0) nbrs[v].push_back(id(i, j - 1));\n                if (j + 1 < D) nbrs[v].push_back(id(i, j + 1));\n            }\n        }\n    }\n\n    void finalize_init() {\n        free_ids.clear();\n        for (int i = 0; i < D * D; ++i) {\n            if (i == entrance) continue;\n            if (obstacle[i]) continue;\n            free_ids.push_back(i);\n        }\n        M = (int)free_ids.size();\n        used.assign(M, 0);\n        current_empty_count = M + 1; // all free cells + entrance\n    }\n\n    bool connected_after_occupy(const array<char, 81>& occ, int empty_count, int ban) const {\n        // Check whether passable cells (entrance + empty cells except ban) stay connected.\n        array<char, 81> vis{};\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n        int cnt = 1;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (vis[to]) continue;\n                if (to == ban) continue;\n                if (obstacle[to]) continue;\n                if (occ[to]) continue;\n                vis[to] = 1;\n                q[qt++] = to;\n                ++cnt;\n            }\n        }\n        return cnt == empty_count - 1;\n    }\n\n    vector<int> legal_cells(const array<char, 81>& occ, int empty_count) const {\n        vector<int> res;\n        res.reserve(empty_count);\n        for (int v : free_ids) {\n            if (occ[v]) continue;\n            if (connected_after_occupy(occ, empty_count, v)) res.push_back(v);\n        }\n        return res;\n    }\n\n    vector<int> bfs_dist_empty(const array<char, 81>& occ) const {\n        vector<int> dist(D * D, -1);\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        dist[entrance] = 0;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (dist[to] != -1) continue;\n                if (obstacle[to]) continue;\n                if (occ[to]) continue;\n                dist[to] = dist[v] + 1;\n                q[qt++] = to;\n            }\n        }\n        return dist;\n    }\n\n    int current_degree_empty(int v, const array<char, 81>& occ) const {\n        int deg = 0;\n        for (int to : nbrs[v]) {\n            if (obstacle[to]) continue;\n            if (occ[to]) continue;\n            ++deg;\n        }\n        return deg;\n    }\n\n    vector<int> dynamic_estimated_output_rank() const {\n        // Estimate future output order for remaining empty cells:\n        // peel legal cells from far away to near core; reverse peel = estimated output order.\n        array<char, 81> temp_occ = occupied;\n        int empty_count = current_empty_count;\n        int rem = empty_count - 1; // excluding entrance\n\n        vector<int> est_rank(D * D, -1);\n\n        for (int step = 0; step < rem; ++step) {\n            auto dist = bfs_dist_empty(temp_occ);\n            auto legal = legal_cells(temp_occ, empty_count);\n\n            int best = -1;\n            int bestDist = -1;\n            int bestDeg = 100;\n            int bestMan = -1;\n\n            for (int v : legal) {\n                int dv = dist[v];\n                int deg = current_degree_empty(v, temp_occ);\n                int man = row(v) + abs(col(v) - mid);\n\n                if (best == -1 ||\n                    dv > bestDist ||\n                    (dv == bestDist && deg < bestDeg) ||\n                    (dv == bestDist && deg == bestDeg && man > bestMan) ||\n                    (dv == bestDist && deg == bestDeg && man == bestMan && v < best)) {\n                    best = v;\n                    bestDist = dv;\n                    bestDeg = deg;\n                    bestMan = man;\n                }\n            }\n\n            est_rank[best] = rem - 1 - step; // 0 = early estimated output, larger = later\n            temp_occ[best] = 1;\n            --empty_count;\n        }\n        return est_rank;\n    }\n\n    int rank_among_remaining_labels(int t) const {\n        int r = 0;\n        for (int x = 0; x < t; ++x) {\n            if (!used[x]) ++r;\n        }\n        return r;\n    }\n\n    int choose_place(int t) const {\n        auto est_rank = dynamic_estimated_output_rank();\n        auto legal = legal_cells(occupied, current_empty_count);\n        int r = rank_among_remaining_labels(t);\n\n        int best = -1;\n        tuple<long long, int, int, int, int> best_key;\n\n        for (int v : legal) {\n            long long diff = llabs((long long)est_rank[v] - r);\n            int later_penalty = (est_rank[v] > r) ? 1 : 0; // prefer slightly earlier slots on tie\n            int man = row(v) + abs(col(v) - mid);\n            auto key = make_tuple(diff, later_penalty, est_rank[v], -man, v);\n            if (best == -1 || key < best_key) {\n                best = v;\n                best_key = key;\n            }\n        }\n        return best;\n    }\n\n    int choose_remove() const {\n        array<char, 81> vis{};\n        int q[81];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n\n        int best = -1;\n        array<char, 81> added{};\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (obstacle[to]) continue;\n                if (occupied[to]) {\n                    if (!added[to]) {\n                        added[to] = 1;\n                        if (best == -1 || label_at[to] < label_at[best]) best = to;\n                    }\n                } else {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[qt++] = to;\n                    }\n                }\n            }\n        }\n        return best;\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    Solver solver(D, N);\n\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        solver.obstacle[solver.id(r, c)] = 1;\n    }\n    solver.finalize_init();\n\n    for (int d = 0; d < solver.M; ++d) {\n        int t;\n        cin >> t;\n\n        int v = solver.choose_place(t);\n\n        solver.occupied[v] = 1;\n        solver.label_at[v] = t;\n        solver.used[t] = 1;\n        --solver.current_empty_count;\n\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n' << flush;\n    }\n\n    for (int k = 0; k < solver.M; ++k) {\n        int v = solver.choose_remove();\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n';\n        solver.occupied[v] = 0;\n    }\n    cout << flush;\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXC = 100;\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 DeltaPack {\n    int u[16], v[16], d[16];\n    int sz = 0;\n\n    void clear() { sz = 0; }\n\n    void add(int a, int b, int val) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < sz; i++) {\n            if (u[i] == a && v[i] == b) {\n                d[i] += val;\n                return;\n            }\n        }\n        u[sz] = a;\n        v[sz] = b;\n        d[sz] = val;\n        sz++;\n    }\n};\n\nstruct Solver {\n    int n, m;\n    int orig[MAXN][MAXN];\n    bool target[MAXC + 1][MAXC + 1]{};\n\n    int g[MAXN][MAXN];\n    int bestg[MAXN][MAXN];\n\n    int area[MAXC + 1]{};\n    int adjcnt[MAXC + 1][MAXC + 1]{};\n\n    int bestZero = 0;\n\n    mt19937 rng;\n\n    static constexpr int DX[4] = {-1, 1, 0, 0};\n    static constexpr int DY[4] = {0, 0, -1, 1};\n\n    Solver() {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < n && 0 <= y && y < n;\n    }\n\n    void build_adj_from_board(int board[MAXN][MAXN], int cnt[MAXC + 1][MAXC + 1]) {\n        for (int i = 0; i <= m; i++) for (int j = 0; j <= m; j++) cnt[i][j] = 0;\n\n        auto add_pair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            cnt[a][b]++;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int c = board[i][j];\n                if (i == 0) add_pair(c, 0);\n                if (j == 0) add_pair(c, 0);\n                if (i + 1 < n) add_pair(c, board[i + 1][j]);\n                else add_pair(c, 0);\n                if (j + 1 < n) add_pair(c, board[i][j + 1]);\n                else add_pair(c, 0);\n            }\n        }\n    }\n\n    void init_target() {\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(orig, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = 0; j <= m; j++) target[i][j] = false;\n        }\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                target[i][j] = target[j][i] = (cnt[i][j] > 0);\n            }\n        }\n    }\n\n    void reset_state() {\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) g[i][j] = orig[i][j];\n        for (int c = 0; c <= m; c++) area[c] = 0;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) area[g[i][j]]++;\n        build_adj_from_board(g, adjcnt);\n        bestZero = area[0];\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = g[i][j];\n    }\n\n    bool can_remove_color_cell(int x, int y) {\n        int c = g[x][y];\n        if (c == 0) return false;\n        if (area[c] <= 1) return false;\n\n        pair<int,int> same[4];\n        int k = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == c) same[k++] = {nx, ny};\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        static int vis[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        q.push(same[0]);\n        vis[same[0].first][same[0].second] = stamp;\n        int cnt = 0;\n\n        while (!q.empty()) {\n            auto [cx, cy] = q.front();\n            q.pop();\n            cnt++;\n            if (cnt == area[c] - 1) return true;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = cx + DX[dir], ny = cy + DY[dir];\n                if (!inside(nx, ny)) continue;\n                if (nx == x && ny == y) continue;\n                if (g[nx][ny] != c) continue;\n                if (vis[nx][ny] == stamp) continue;\n                vis[nx][ny] = stamp;\n                q.push({nx, ny});\n            }\n        }\n        return cnt == area[c] - 1;\n    }\n\n    bool can_attach_zero(int x, int y) const {\n        if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return true;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == 0) return true;\n        }\n        return false;\n    }\n\n    bool check_move(int x, int y, int t, int &deltaPerim, DeltaPack &pack) {\n        int c = g[x][y];\n        if (c == 0 || c == t) return false;\n\n        if (t == 0) {\n            if (!can_attach_zero(x, y)) return false;\n        } else {\n            bool touch = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (inside(nx, ny) && g[nx][ny] == t) {\n                    touch = true;\n                    break;\n                }\n            }\n            if (!touch) return false;\n        }\n\n        pack.clear();\n        deltaPerim = 0;\n\n        auto process_side = [&](int other) {\n            deltaPerim += (t != other) - (c != other);\n            pack.add(c, other, -1);\n            pack.add(t, other, +1);\n        };\n\n        if (x > 0) process_side(g[x - 1][y]);\n        else process_side(0);\n        if (x + 1 < n) process_side(g[x + 1][y]);\n        else process_side(0);\n        if (y > 0) process_side(g[x][y - 1]);\n        else process_side(0);\n        if (y + 1 < n) process_side(g[x][y + 1]);\n        else process_side(0);\n\n        for (int i = 0; i < pack.sz; i++) {\n            int a = pack.u[i], b = pack.v[i];\n            int after = adjcnt[a][b] + pack.d[i];\n            if ((after > 0) != target[a][b]) return false;\n        }\n        return true;\n    }\n\n    void apply_move(int x, int y, int t, const DeltaPack &pack) {\n        int c = g[x][y];\n        area[c]--;\n        area[t]++;\n        g[x][y] = t;\n        for (int i = 0; i < pack.sz; i++) {\n            adjcnt[pack.u[i]][pack.v[i]] += pack.d[i];\n        }\n        if (area[0] > bestZero) {\n            bestZero = area[0];\n            for (int r = 0; r < n; r++) for (int c2 = 0; c2 < n; c2++) bestg[r][c2] = g[r][c2];\n        }\n    }\n\n    bool try_zero_move(int x, int y) {\n        if (!inside(x, y)) return false;\n        if (g[x][y] == 0) return false;\n        if (!can_remove_color_cell(x, y)) return false;\n        int dp;\n        DeltaPack pack;\n        if (!check_move(x, y, 0, dp, pack)) return false;\n        apply_move(x, y, 0, pack);\n        return true;\n    }\n\n    void harvest_local(const vector<pair<int,int>> &seeds) {\n        static int seen[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        auto push = [&](int x, int y) {\n            if (!inside(x, y)) return;\n            if (seen[x][y] == stamp) return;\n            seen[x][y] = stamp;\n            q.push({x, y});\n        };\n\n        for (auto [x, y] : seeds) {\n            push(x, y);\n            for (int dir = 0; dir < 4; dir++) push(x + DX[dir], y + DY[dir]);\n        }\n\n        while (!q.empty()) {\n            auto [x, y] = q.front();\n            q.pop();\n            if (!inside(x, y)) continue;\n            if (g[x][y] == 0) continue;\n            if (try_zero_move(x, y)) {\n                push(x, y);\n                for (int dir = 0; dir < 4; dir++) {\n                    push(x + DX[dir], y + DY[dir]);\n                    push(x + 2 * DX[dir], y + 2 * DY[dir]);\n                }\n            }\n        }\n    }\n\n    int strict_sweep_once() {\n        vector<int> ord(n * n);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        int changes = 0;\n\n        for (int id : ord) {\n            int x = id / n, y = id % n;\n            if (g[x][y] == 0) continue;\n\n            if (try_zero_move(x, y)) {\n                changes++;\n                continue;\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int bestT = -1, bestDP = 100;\n            DeltaPack bestPack;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == g[x][y] || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                if (dp < bestDP) {\n                    bestDP = dp;\n                    bestT = t;\n                    bestPack = pack;\n                }\n            }\n\n            if (bestT != -1) {\n                bool accept = false;\n                if (bestDP < 0) accept = true;\n                else if (bestDP == 0 && (rng() & 3) == 0) accept = true;\n\n                if (accept) {\n                    apply_move(x, y, bestT, bestPack);\n                    harvest_local({{x, y}});\n                    changes++;\n                }\n            }\n        }\n\n        return changes;\n    }\n\n    void run_search(double limit_sec, const Timer &timer) {\n        reset_state();\n\n        while (timer.elapsed() < limit_sec * 0.25) {\n            int ch = strict_sweep_once();\n            if (ch == 0) break;\n        }\n\n        uniform_int_distribution<int> cellDist(0, n * n - 1);\n\n        long long iter = 0;\n        long long lastImproveIter = 0;\n        int localBest = bestZero;\n\n        while (timer.elapsed() < limit_sec) {\n            iter++;\n\n            if ((iter % 3000) == 0) {\n                int ch = strict_sweep_once();\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n                if (ch == 0 && iter - lastImproveIter > 20000) {\n                    // Mild reshuffle via another sweep; no reset, just continue.\n                    strict_sweep_once();\n                    lastImproveIter = iter;\n                }\n            }\n\n            int id = cellDist(rng);\n            int x = id / n, y = id % n;\n            int c = g[x][y];\n            if (c == 0) continue;\n\n            if ((iter & 7) == 0) {\n                if (try_zero_move(x, y)) {\n                    harvest_local({{x, y}});\n                    if (bestZero > localBest) {\n                        localBest = bestZero;\n                        lastImproveIter = iter;\n                    }\n                    continue;\n                }\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int candT[4], candDP[4], candK = 0;\n            DeltaPack candPack[4];\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == c || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                candT[candK] = t;\n                candDP[candK] = dp;\n                candPack[candK] = pack;\n                candK++;\n            }\n\n            if (candK == 0) continue;\n\n            int pick = 0;\n            if (candK >= 2 && (rng() % 100) < 35) {\n                pick = rng() % candK;\n            } else {\n                for (int i = 1; i < candK; i++) {\n                    if (candDP[i] < candDP[pick]) pick = i;\n                }\n            }\n\n            int dp = candDP[pick];\n            double t01 = timer.elapsed() / limit_sec;\n            double temp = 1.8 * (1.0 - t01) + 0.03 * t01;\n\n            bool accept = false;\n            if (dp <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-double(dp) / temp);\n                uint32_t rv = rng();\n                double u = (rv + 0.5) * (1.0 / 4294967296.0);\n                if (u < prob) accept = true;\n            }\n\n            if (accept) {\n                apply_move(x, y, candT[pick], candPack[pick]);\n                harvest_local({{x, y}});\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n            }\n        }\n    }\n\n    bool full_validate(int board[MAXN][MAXN]) {\n        int cntArea[MAXC + 1] = {};\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cntArea[board[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cntArea[c] == 0) return false;\n\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(board, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                bool cur = cnt[i][j] > 0;\n                if (cur != target[i][j]) return false;\n            }\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // Positive colors connectivity\n        vector<vector<int>> vis(n, vector<int>(n, -1));\n        for (int c = 1; c <= m; c++) {\n            pair<int,int> st = {-1, -1};\n            for (int i = 0; i < n && st.first == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (board[i][j] == c) {\n                        st = {i, j};\n                        break;\n                    }\n                }\n            }\n            if (st.first == -1) return false;\n\n            queue<pair<int,int>> q;\n            q.push(st);\n            vis[st.first][st.second] = c;\n            int got = 0;\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != c || vis[nx][ny] == c) continue;\n                    vis[nx][ny] = c;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[c]) return false;\n        }\n\n        // Zero connectivity through outside = every zero cell must connect to boundary zero.\n        if (cntArea[0] > 0) {\n            vector<vector<int>> zvis(n, vector<int>(n, 0));\n            queue<pair<int,int>> q;\n            int got = 0;\n\n            for (int i = 0; i < n; i++) {\n                for (int j : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n            for (int j = 0; j < n; j++) {\n                for (int i : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != 0 || zvis[nx][ny]) continue;\n                    zvis[nx][ny] = 1;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[0]) return false;\n        }\n\n        return true;\n    }\n\n    void solve() {\n        cin >> n >> m;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) cin >> orig[i][j];\n        }\n\n        init_target();\n\n        Timer timer;\n        const double TL = 1.92;\n\n        run_search(TL, timer);\n\n        if (!full_validate(bestg)) {\n            for (int i = 0; i < n; i++) {\n                for (int j = 0; j < n; j++) {\n                    cout << orig[i][j] << (j + 1 == n ? '\\n' : ' ');\n                }\n            }\n            return;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                cout << bestg[i][j] << (j + 1 == n ? '\\n' : ' ');\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Bin {\n    vector<int> items;\n    long double est_load = 0;\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int lgD = 0;\n\n    vector<int> insc;                  // insertion-sort exact cost for prefix size k\n    vector<long double> H;             // harmonic numbers\n    vector<long double> est_by_pos;    // estimated weight by rank position\n    vector<long double> est_by_item;   // estimated weight by item after final order chosen\n\n    static int ceil_log2_int(int x) {\n        int k = 0, p = 1;\n        while (p < x) p <<= 1, ++k;\n        return k;\n    }\n\n    int ask(const vector<int>& L, const vector<int>& R) {\n        // Must be non-empty and disjoint.\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        cin >> s;\n        ++used;\n        if (s == \"<\") return -1;\n        if (s == \">\") return 1;\n        return 0;\n    }\n\n    int cmp_item(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask(L, R);\n    }\n\n    vector<int> exact_sort_items(const vector<int>& items) {\n        // Descending order: heavier first.\n        vector<int> sorted;\n        sorted.reserve(items.size());\n        for (int x : items) {\n            int l = 0, r = (int)sorted.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = cmp_item(x, sorted[m]);\n                if (c > 0) r = m;      // x heavier -> go left\n                else l = m + 1;        // x <= sorted[m] -> go right\n            }\n            sorted.insert(sorted.begin() + l, x);\n        }\n        return sorted;\n    }\n\n    vector<int> tournament_order() {\n        vector<int> depth(N, 0);\n        vector<int> cur(N);\n        iota(cur.begin(), cur.end(), 0);\n\n        int round = 0;\n        while ((int)cur.size() > 1) {\n            vector<int> nxt;\n            nxt.reserve((cur.size() + 1) / 2);\n            for (int i = 0; i + 1 < (int)cur.size(); i += 2) {\n                int a = cur[i], b = cur[i + 1];\n                int c = cmp_item(a, b);\n                int winner, loser;\n                if (c >= 0) {\n                    winner = a;\n                    loser = b;\n                } else {\n                    winner = b;\n                    loser = a;\n                }\n                depth[loser] = round;\n                nxt.push_back(winner);\n            }\n            if ((int)cur.size() & 1) nxt.push_back(cur.back());\n            cur.swap(nxt);\n            ++round;\n        }\n        depth[cur[0]] = round;\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (depth[a] != depth[b]) return depth[a] > depth[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<Bin> estimated_assign_all(const vector<int>& order, int fixed_prefix = 0) {\n        vector<Bin> bins(D);\n        for (int p = 0; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_by_item[item];\n        }\n        return bins;\n    }\n\n    vector<Bin> hybrid_assign(const vector<int>& order, int K) {\n        // First K items are handled with exact order.\n        // Top D initialize bins; next K-D items are assigned to actual lightest bin\n        // using real bin-sum comparisons; the rest are assigned by estimated weights.\n        if (K < D) {\n            return estimated_assign_all(order);\n        }\n\n        vector<Bin> bins(D);\n\n        // order is exact descending at least for [0, K)\n        // So actual ascending among first D is reverse order.\n        for (int j = 0; j < D; ++j) {\n            int item = order[D - 1 - j];\n            bins[j].items.push_back(item);\n            bins[j].est_load += est_by_item[item];\n        }\n\n        for (int p = D; p < K; ++p) {\n            Bin cur = std::move(bins[0]);\n            bins.erase(bins.begin());\n\n            int item = order[p];\n            cur.items.push_back(item);\n            cur.est_load += est_by_item[item];\n\n            int l = 0, r = (int)bins.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = ask(cur.items, bins[m].items); // compare actual sums\n                if (c <= 0) r = m; // cur <= bins[m] => go left\n                else l = m + 1;\n            }\n            bins.insert(bins.begin() + l, std::move(cur));\n        }\n\n        // Remaining items: estimated greedy.\n        for (int p = K; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_by_item[item];\n        }\n\n        return bins;\n    }\n\n    static void erase_one(vector<int>& v, int x) {\n        for (int i = 0; i < (int)v.size(); ++i) {\n            if (v[i] == x) {\n                v.erase(v.begin() + i);\n                return;\n            }\n        }\n    }\n\n    void local_improve(vector<Bin>& bins, const vector<char>& fixed) {\n        for (int iter = 0; iter < 300; ++iter) {\n            int hi = 0, lo = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load > bins[hi].est_load) hi = j;\n                if (bins[j].est_load < bins[lo].est_load) lo = j;\n            }\n            if (hi == lo) break;\n\n            long double A = bins[hi].est_load;\n            long double B = bins[lo].est_load;\n            long double best_diff = fabsl(A - B);\n\n            int best_type = 0; // 0 none, 1 move x hi->lo, 2 swap x<->y\n            int bx = -1, by = -1;\n\n            // Move one item from heavy to light\n            if ((int)bins[hi].items.size() > 1) {\n                for (int x : bins[hi].items) {\n                    if (fixed[x]) continue;\n                    long double w = est_by_item[x];\n                    long double nd = fabsl((A - w) - (B + w));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        best_type = 1;\n                        bx = x;\n                        by = -1;\n                    }\n                }\n            }\n\n            // Swap one item\n            for (int x : bins[hi].items) {\n                if (fixed[x]) continue;\n                long double wx = est_by_item[x];\n                for (int y : bins[lo].items) {\n                    if (fixed[y]) continue;\n                    long double wy = est_by_item[y];\n                    long double nd = fabsl((A - wx + wy) - (B - wy + wx));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        best_type = 2;\n                        bx = x;\n                        by = y;\n                    }\n                }\n            }\n\n            if (best_type == 0) break;\n\n            if (best_type == 1) {\n                erase_one(bins[hi].items, bx);\n                bins[lo].items.push_back(bx);\n                long double w = est_by_item[bx];\n                bins[hi].est_load -= w;\n                bins[lo].est_load += w;\n            } else {\n                erase_one(bins[hi].items, bx);\n                erase_one(bins[lo].items, by);\n                bins[hi].items.push_back(by);\n                bins[lo].items.push_back(bx);\n                long double wx = est_by_item[bx];\n                long double wy = est_by_item[by];\n                bins[hi].est_load += wy - wx;\n                bins[lo].est_load += wx - wy;\n            }\n        }\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        lgD = ceil_log2_int(D);\n\n        insc.assign(N + 1, 0);\n        for (int k = 2; k <= N; ++k) insc[k] = insc[k - 1] + ceil_log2_int(k);\n\n        H.assign(N + 1, 0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0L / i;\n\n        est_by_pos.assign(N, 0);\n        for (int p = 0; p < N; ++p) {\n            est_by_pos[p] = H[N] - H[p];\n        }\n\n        vector<int> order;\n        int K_actual = 0;\n\n        if (Q >= insc[N]) {\n            // Exact sort all items, then use remaining queries for exact bin placement\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            order = exact_sort_items(all);\n\n            int rem = Q - used;\n            K_actual = D;\n            if (lgD > 0) {\n                K_actual = min(N, D + rem / lgD);\n            } else {\n                K_actual = N;\n            }\n        } else {\n            // Tournament coarse order first\n            vector<int> coarse = tournament_order();\n            int R = Q - used;\n\n            int Mbest = 0;\n            for (int m = 0; m <= N; ++m) {\n                if (insc[m] <= R) Mbest = m;\n            }\n\n            int Kbest = 0;\n            for (int k = D; k <= N; ++k) {\n                long long need = (long long)insc[k] + 1LL * (k - D) * lgD;\n                if (need <= R) Kbest = k;\n            }\n\n            long double utilA = -1e100L;\n            if (Kbest >= D) {\n                utilA = (long double)Kbest + (long double)(Kbest - D) * (2.0L / max(1, lgD));\n            }\n            long double utilB = (long double)Mbest;\n\n            int M = 0;\n            if (Kbest >= D && utilA > utilB) {\n                M = Kbest;\n                K_actual = Kbest;\n            } else {\n                M = Mbest;\n                K_actual = 0;\n            }\n\n            vector<int> prefix(coarse.begin(), coarse.begin() + M);\n            vector<int> exact_prefix = exact_sort_items(prefix);\n\n            order.reserve(N);\n            for (int x : exact_prefix) order.push_back(x);\n            for (int i = M; i < N; ++i) order.push_back(coarse[i]);\n        }\n\n        // Estimated weight per item from final approximate order position\n        est_by_item.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_by_item[order[p]] = est_by_pos[p];\n\n        vector<Bin> bins;\n        vector<char> fixed(N, 0);\n\n        if (K_actual >= D) {\n            for (int p = 0; p < K_actual; ++p) fixed[order[p]] = 1;\n            bins = hybrid_assign(order, K_actual);\n        } else {\n            bins = estimated_assign_all(order);\n        }\n\n        local_improve(bins, fixed);\n\n        // Fill remaining queries with dummy queries\n        while (used < Q) {\n            vector<int> L{0}, R{1};\n            ask(L, R);\n        }\n\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b].items) ans[x] = b;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Policy {\n    int max_chunks;\n\n    int move_penalty;\n    int seg_inv_w;\n    int seg_adj_w;\n\n    int dest_inv_w;\n    int fit_w;\n    int top_w;\n    int size_w;\n    int empty_bonus;\n\n    int bad_fit_base;\n    int bad_fit_mul;\n\n    int gen_pen1, gen_pen2, gen_pen3;\n    bool use_dec_runs;\n};\n\nstruct Result {\n    long long energy;\n    vector<pair<int,int>> ops;\n};\n\nstruct Simulator {\n    int n, m;\n    vector<vector<int>> init_st;\n\n    Simulator(int n_, int m_, const vector<vector<int>>& st_) : n(n_), m(m_), init_st(st_) {}\n\n    static 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    int urgency(int x, int cur) const {\n        int d = x - cur;\n        if (d <= 10) return 5;\n        if (d <= 20) return 4;\n        if (d <= 40) return 3;\n        if (d <= 80) return 2;\n        return 1;\n    }\n\n    void remove_possible(vector<vector<int>>& st, vector<pair<int,int>>& ops, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ops.push_back({cur, 0});\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    pair<int,int> find_box(const vector<vector<int>>& st, int v) const {\n        for (int i = 0; i < m; 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    long long cross_inv_cost(const vector<int>& dst, const vector<int>& chunk, int cur) const {\n        long long c = 0;\n        for (int x : dst) {\n            int w = urgency(x, cur);\n            for (int y : chunk) {\n                if (x < y) c += w;\n            }\n        }\n        return c;\n    }\n\n    vector<pair<int,int>> decode_mask(int t, uint32_t mask) const {\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if ((mask >> i) & 1U) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n        return segs;\n    }\n\n    uint32_t encode_segs(const vector<pair<int,int>>& segs) const {\n        uint32_t mask = 0;\n        for (int i = 0; i + 1 < (int)segs.size(); i++) {\n            mask |= (1U << segs[i].second);\n        }\n        return mask;\n    }\n\n    uint32_t partition_by_metric(const vector<vector<long long>>& metric, int t, int max_chunks, int pen) const {\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> dp(max_chunks + 1, vector<long long>(t + 1, INF));\n        vector<vector<int>> prv(max_chunks + 1, vector<int>(t + 1, -1));\n        dp[0][0] = 0;\n        for (int k = 1; k <= max_chunks; k++) {\n            for (int i = 1; i <= t; i++) {\n                for (int l = 0; l < i; l++) {\n                    if (dp[k - 1][l] == INF) continue;\n                    long long cand = dp[k - 1][l] + metric[l][i - 1] + pen;\n                    if (cand < dp[k][i]) {\n                        dp[k][i] = cand;\n                        prv[k][i] = l;\n                    }\n                }\n            }\n        }\n        int best_k = 1;\n        long long best = dp[1][t];\n        for (int k = 2; k <= max_chunks; k++) {\n            if (dp[k][t] < best) {\n                best = dp[k][t];\n                best_k = k;\n            }\n        }\n        vector<pair<int,int>> rev;\n        int i = t, k = best_k;\n        while (k > 0) {\n            int l = prv[k][i];\n            rev.push_back({l, i - 1});\n            i = l;\n            --k;\n        }\n        reverse(rev.begin(), rev.end());\n        return encode_segs(rev);\n    }\n\n    uint32_t decreasing_runs_mask(const vector<int>& b, int max_chunks,\n                                  const vector<vector<long long>>& merge_metric) const {\n        int t = (int)b.size();\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if (b[i] < b[i + 1]) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n\n        while ((int)segs.size() > max_chunks) {\n            long long best_add = (1LL << 60);\n            int best_i = -1;\n            for (int i = 0; i + 1 < (int)segs.size(); i++) {\n                int l0 = segs[i].first;\n                int r0 = segs[i].second;\n                int l1 = segs[i + 1].first;\n                int r1 = segs[i + 1].second;\n                long long add = merge_metric[l0][r1] - merge_metric[l0][r0] - merge_metric[l1][r1];\n                if (add < best_add) {\n                    best_add = add;\n                    best_i = i;\n                }\n            }\n            segs[best_i].second = segs[best_i + 1].second;\n            segs.erase(segs.begin() + best_i + 1);\n        }\n        return encode_segs(segs);\n    }\n\n    bool assign_unique_destinations(\n        const vector<vector<int>>& st,\n        int src,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        vector<int>& dest_of_seg,\n        long long& min_cost\n    ) const {\n        int k = (int)segs.size();\n        const long long INF = (1LL << 60);\n\n        vector<vector<long long>> cost(k, vector<long long>(m, INF));\n\n        for (int sidx = 0; sidx < k; sidx++) {\n            int l = segs[sidx].first, r = segs[sidx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n            int chunk_bottom = chunk.front();\n\n            for (int d = 0; d < m; d++) {\n                if (d == src) continue;\n\n                long long c = 0;\n                c += 1LL * P.dest_inv_w * cross_inv_cost(st[d], chunk, cur);\n                c += 1LL * P.size_w * (int)st[d].size();\n\n                if (st[d].empty()) {\n                    c -= P.empty_bonus;\n                } else {\n                    int top = st[d].back();\n                    int fit_pen = 0;\n                    if (top > chunk_bottom) fit_pen = top - chunk_bottom;\n                    else fit_pen = P.bad_fit_base + P.bad_fit_mul * (chunk_bottom - top);\n                    c += 1LL * P.fit_w * fit_pen;\n\n                    int soon = max(0, 35 - (top - cur));\n                    c += 1LL * P.top_w * soon;\n                }\n                cost[sidx][d] = c;\n            }\n        }\n\n        vector<vector<long long>> dp(k + 1, vector<long long>(1 << m, INF));\n        vector<vector<int>> prv_mask(k + 1, vector<int>(1 << m, -1));\n        vector<vector<int>> prv_dst(k + 1, vector<int>(1 << m, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < k; i++) {\n            for (int mask = 0; mask < (1 << m); mask++) {\n                if (dp[i][mask] == INF) continue;\n                for (int d = 0; d < m; d++) {\n                    if (d == src) continue;\n                    if ((mask >> d) & 1) continue;\n                    long long cand = dp[i][mask] + cost[i][d];\n                    int nmask = mask | (1 << d);\n                    if (cand < dp[i + 1][nmask]) {\n                        dp[i + 1][nmask] = cand;\n                        prv_mask[i + 1][nmask] = mask;\n                        prv_dst[i + 1][nmask] = d;\n                    }\n                }\n            }\n        }\n\n        min_cost = INF;\n        int best_mask = -1;\n        for (int mask = 0; mask < (1 << m); mask++) {\n            if (dp[k][mask] < min_cost) {\n                min_cost = dp[k][mask];\n                best_mask = mask;\n            }\n        }\n        if (best_mask == -1) return false;\n\n        dest_of_seg.assign(k, -1);\n        int mask = best_mask;\n        for (int i = k; i >= 1; i--) {\n            dest_of_seg[i - 1] = prv_dst[i][mask];\n            mask = prv_mask[i][mask];\n        }\n        return true;\n    }\n\n    Result run_one(const Policy& P, XorShift64& rng) const {\n        vector<vector<int>> st = init_st;\n        vector<pair<int,int>> ops;\n        long long energy = 0;\n        int cur = 1;\n\n        remove_possible(st, ops, cur);\n\n        while (cur <= n) {\n            auto [src, pos] = find_box(st, cur);\n            vector<int> blockers(st[src].begin() + pos + 1, st[src].end());\n            int t = (int)blockers.size();\n\n            if (t == 0) {\n                remove_possible(st, ops, cur);\n                continue;\n            }\n\n            vector<vector<long long>> invw(t, vector<long long>(t, 0));\n            vector<vector<long long>> adjv(t, vector<long long>(t, 0));\n\n            for (int l = 0; l < t; l++) {\n                long long inv = 0, adj = 0;\n                for (int r = l; r < t; r++) {\n                    if (r > l && blockers[r - 1] < blockers[r]) adj++;\n                    for (int i = l; i < r; i++) {\n                        if (blockers[i] < blockers[r]) inv += urgency(blockers[i], cur);\n                    }\n                    invw[l][r] = inv;\n                    adjv[l][r] = adj;\n                }\n            }\n\n            vector<uint32_t> cand_masks;\n            auto add_mask = [&](uint32_t mask) {\n                cand_masks.push_back(mask);\n            };\n\n            add_mask(0); // single chunk\n\n            if (P.use_dec_runs) {\n                add_mask(decreasing_runs_mask(blockers, P.max_chunks, invw));\n            }\n            add_mask(partition_by_metric(invw, t, P.max_chunks, P.gen_pen1));\n            add_mask(partition_by_metric(invw, t, P.max_chunks, P.gen_pen2));\n            add_mask(partition_by_metric(adjv, t, P.max_chunks, P.gen_pen3));\n\n            sort(cand_masks.begin(), cand_masks.end());\n            cand_masks.erase(unique(cand_masks.begin(), cand_masks.end()), cand_masks.end());\n\n            long long best_score = (1LL << 60);\n            vector<pair<int,int>> best_segs;\n            vector<int> best_dest;\n\n            for (uint32_t mask : cand_masks) {\n                auto segs = decode_mask(t, mask);\n                int k = (int)segs.size();\n                if (k > P.max_chunks || k > m - 1) continue;\n\n                long long internal_inv = 0, internal_adj = 0;\n                for (auto [l, r] : segs) {\n                    internal_inv += invw[l][r];\n                    internal_adj += adjv[l][r];\n                }\n\n                vector<int> dests;\n                long long assign_cost;\n                if (!assign_unique_destinations(st, src, cur, segs, blockers, P, dests, assign_cost)) continue;\n\n                long long score = 0;\n                score += 1LL * P.move_penalty * k;\n                score += 1LL * P.seg_inv_w * internal_inv;\n                score += 1LL * P.seg_adj_w * internal_adj;\n                score += assign_cost;\n                score += rng.next_int(0, 2); // tiny tie-break noise\n\n                if (score < best_score) {\n                    best_score = score;\n                    best_segs = segs;\n                    best_dest = dests;\n                }\n            }\n\n            if (best_segs.empty()) {\n                best_segs = {{0, t - 1}};\n                best_dest = { (src == 0 ? 1 : 0) };\n            }\n\n            for (int idx = (int)best_segs.size() - 1; idx >= 0; idx--) {\n                int l = best_segs[idx].first;\n                int start = pos + 1 + l;\n                int dst = best_dest[idx];\n\n                int moved = (int)st[src].size() - start;\n                energy += moved + 1;\n                ops.push_back({st[src][start], dst + 1});\n\n                vector<int> seg(st[src].begin() + start, st[src].end());\n                st[src].erase(st[src].begin() + start, st[src].end());\n                st[dst].insert(st[dst].end(), seg.begin(), seg.end());\n            }\n\n            remove_possible(st, ops, cur);\n        }\n\n        return {energy, ops};\n    }\n\n    Result solve() const {\n        uint64_t seed = 0x123456789abcdef0ULL;\n        for (const auto& s : init_st) for (int x : s) seed = splitmix64(seed ^ (uint64_t)x);\n        XorShift64 rng(seed);\n\n        vector<Policy> bases = {\n            {4, 7, 2, 8, 6, 2, 4, 1, 6, 18, 3, 3, 6, 10, true},\n            {5, 5, 2, 6, 7, 2, 3, 1, 8, 20, 3, 2, 4, 7,  true},\n            {4, 9, 3, 10,5, 3, 5, 1, 4, 22, 4, 4, 8, 12, true},\n            {5, 6, 1, 12,4, 4, 6, 1, 7, 25, 4, 3, 5, 9,  true},\n            {4, 8, 4, 7, 8, 1, 3, 1, 5, 16, 2, 4, 7, 11, false},\n            {5, 4, 1, 5, 9, 2, 2, 1, 10,18, 3, 2, 3, 6,  true}\n        };\n\n        Result best{(1LL << 60), {}};\n\n        auto start_time = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            auto now = chrono::steady_clock::now();\n            return chrono::duration<double, milli>(now - start_time).count();\n        };\n\n        for (const auto& p : bases) {\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        while (elapsed_ms() < 1750.0) {\n            Policy p = bases[rng.next_int(0, (int)bases.size() - 1)];\n\n            auto perturb = [&](int v, int d, int lo, int hi) {\n                return max(lo, min(hi, v + rng.next_int(-d, d)));\n            };\n\n            p.max_chunks   = perturb(p.max_chunks,   1, 3, 5);\n            p.move_penalty = perturb(p.move_penalty, 2, 2, 12);\n            p.seg_inv_w    = perturb(p.seg_inv_w,    2, 0, 6);\n            p.seg_adj_w    = perturb(p.seg_adj_w,    4, 0, 15);\n            p.dest_inv_w   = perturb(p.dest_inv_w,   3, 1, 12);\n            p.fit_w        = perturb(p.fit_w,        2, 0, 8);\n            p.top_w        = perturb(p.top_w,        3, 0, 10);\n            p.size_w       = perturb(p.size_w,       1, 0, 4);\n            p.empty_bonus  = perturb(p.empty_bonus,  4, 0, 15);\n            p.bad_fit_base = perturb(p.bad_fit_base, 6, 8, 35);\n            p.bad_fit_mul  = perturb(p.bad_fit_mul,  1, 1, 6);\n            p.gen_pen1     = perturb(p.gen_pen1,     2, 1, 10);\n            p.gen_pen2     = perturb(p.gen_pen2,     3, 2, 14);\n            p.gen_pen3     = perturb(p.gen_pen3,     3, 1, 14);\n            if (p.gen_pen1 > p.gen_pen2) swap(p.gen_pen1, p.gen_pen2);\n            p.use_dec_runs = (rng.next() & 1ULL) ? p.use_dec_runs : !p.use_dec_runs;\n\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        return best;\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>> st(m, vector<int>(n / m));\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < n / m; j++) cin >> st[i][j];\n    }\n\n    Simulator sim(n, m, st);\n    Result res = sim.solve();\n\n    for (auto [v, i] : res.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(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() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct EvalResult {\n    long double score;\n    vector<long long> contrib;\n    vector<int> cnt;\n};\n\nstruct Params {\n    double a_pot;\n    double b_deg;\n    double noise;\n    double straight;\n};\n\nint N, Vn;\nvector<vector<int>> g;\nvector<int> dirt;\nvector<double> potv;\n\nstatic inline int vid(int r, int c, int N) { return r * N + c; }\n\nbool same_dir(int p, int v, int u) {\n    if (p < 0) return false;\n    int pr = p / N, pc = p % N;\n    int vr = v / N, vc = v % N;\n    int ur = u / N, uc = u % N;\n    return (vr - pr == ur - vr) && (vc - pc == uc - vc);\n}\n\nEvalResult evaluate_route(const vector<int>& seq, bool need_detail = true) {\n    int L = (int)seq.size() - 1;\n\n    vector<int> first(Vn, -1), last(Vn, -1), cnt(Vn, 0);\n    vector<long long> gapsum(Vn, 0);\n\n    for (int t = 1; t <= L; t++) {\n        int v = seq[t];\n        cnt[v]++;\n        if (first[v] == -1) {\n            first[v] = last[v] = t;\n        } else {\n            long long gap = t - last[v];\n            gapsum[v] += gap * (gap - 1) / 2;\n            last[v] = t;\n        }\n    }\n\n    long double total = 0;\n    vector<long long> contrib;\n    if (need_detail) contrib.assign(Vn, 0);\n\n    for (int v = 0; v < Vn; v++) {\n        if (cnt[v] == 0) {\n            // illegal / should not happen\n            EvalResult bad;\n            bad.score = 1e100L;\n            return bad;\n        }\n        long long gap = first[v] + L - last[v];\n        gapsum[v] += gap * (gap - 1) / 2;\n        long long c = gapsum[v] * 1LL * dirt[v];\n        total += (long double)c;\n        if (need_detail) contrib[v] = c;\n    }\n\n    EvalResult res;\n    res.score = total / (long double)L;\n    if (need_detail) {\n        res.contrib = move(contrib);\n        res.cnt = move(cnt);\n    }\n    return res;\n}\n\nvector<int> build_tree_route(const Params& P, RNG& rng) {\n    vector<vector<int>> children(Vn);\n    vector<char> vis(Vn, 0);\n\n    function<void(int,int)> dfs = [&](int v, int p) {\n        vis[v] = 1;\n        while (true) {\n            int best = -1;\n            double best_sc = -1e100;\n\n            for (int to : g[v]) {\n                if (vis[to]) continue;\n                int forward_deg = 0;\n                for (int w : g[to]) {\n                    if (!vis[w] && w != v) forward_deg++;\n                }\n                double sc = P.a_pot * potv[to]\n                          - P.b_deg * forward_deg\n                          + P.noise * rng.next_double();\n                if (same_dir(p, v, to)) sc += P.straight;\n\n                if (sc > best_sc) {\n                    best_sc = sc;\n                    best = to;\n                }\n            }\n            if (best == -1) break;\n            children[v].push_back(best);\n            dfs(best, v);\n        }\n    };\n\n    dfs(0, -1);\n\n    vector<int> seq;\n    seq.reserve(2 * Vn + 5);\n    seq.push_back(0);\n\n    function<void(int)> tour = [&](int v) {\n        for (int to : children[v]) {\n            seq.push_back(to);\n            tour(to);\n            seq.push_back(v);\n        }\n    };\n    tour(0);\n    return seq;\n}\n\nvector<int> apply_shuttle(const vector<int>& seq, int x, int y, int step, int offset) {\n    int L = (int)seq.size() - 1;\n    vector<int> res;\n    res.reserve(seq.size() + 64);\n\n    res.push_back(seq[0]);\n    int occ = 0;\n    bool inserted = false;\n\n    for (int i = 0; i < L; i++) {\n        int cur = seq[i];\n        int nxt = seq[i + 1];\n\n        if (cur == y) {\n            if (occ % step == offset) {\n                res.push_back(x);\n                res.push_back(y);\n                inserted = true;\n            }\n            occ++;\n        }\n        res.push_back(nxt);\n    }\n\n    if (!inserted) return {};\n    if ((int)res.size() - 1 > 100000) return {};\n    return res;\n}\n\nstring seq_to_moves(const vector<int>& seq) {\n    string ans;\n    ans.reserve(seq.size());\n    for (int i = 1; i < (int)seq.size(); i++) {\n        int a = seq[i - 1], b = seq[i];\n        int ar = a / N, ac = a % N;\n        int br = b / N, bc = b % N;\n        if (br == ar - 1 && bc == ac) ans.push_back('U');\n        else if (br == ar + 1 && bc == ac) ans.push_back('D');\n        else if (br == ar && bc == ac - 1) ans.push_back('L');\n        else if (br == ar && bc == ac + 1) ans.push_back('R');\n        else {\n            // Should never happen.\n            ans.push_back('?');\n        }\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    Vn = N * N;\n\n    vector<string> h(N - 1), v(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\n    dirt.assign(Vn, 0);\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirt[vid(i, j, N)];\n        }\n    }\n\n    g.assign(Vn, {});\n    for (int i = 0; i < N - 1; i++) {\n        for (int j = 0; j < N; j++) {\n            if (h[i][j] == '0') {\n                int a = vid(i, j, N);\n                int b = vid(i + 1, j, N);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N - 1; j++) {\n            if (v[i][j] == '0') {\n                int a = vid(i, j, N);\n                int b = vid(i, j + 1, N);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n\n    // Local dirt potential: own dirt + discounted nearby dirt within distance 3.\n    potv.assign(Vn, 0.0);\n    for (int s = 0; s < Vn; s++) {\n        potv[s] += dirt[s];\n        vector<int> dist(Vn, -1);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int x = q.front(); q.pop();\n            if (dist[x] == 3) continue;\n            for (int to : g[x]) {\n                if (dist[to] != -1) continue;\n                dist[to] = dist[x] + 1;\n                q.push(to);\n                if (dist[to] == 1) potv[s] += 0.45 * dirt[to];\n                else if (dist[to] == 2) potv[s] += 0.18 * dirt[to];\n                else if (dist[to] == 3) potv[s] += 0.06 * dirt[to];\n            }\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\n    RNG rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    vector<Params> fixed_params = {\n        {1.00, 220.0,   0.0, 120.0},\n        {1.00, 260.0, 160.0, 120.0},\n        {1.15, 180.0, 200.0, 150.0},\n        {0.85, 320.0, 280.0,  80.0},\n        {1.00, 100.0, 380.0, 200.0},\n        {1.20,  50.0, 450.0, 220.0},\n        {0.90, 420.0, 500.0,  50.0},\n        {1.35, 140.0, 120.0, 100.0}\n    };\n\n    vector<int> best_seq;\n    long double best_score = 1e100L;\n\n    // Initial deterministic candidate.\n    {\n        Params P = fixed_params[0];\n        auto seq = build_tree_route(P, rng);\n        auto ev = evaluate_route(seq, false);\n        best_score = ev.score;\n        best_seq = move(seq);\n    }\n\n    // Randomized tree search.\n    int iter = 0;\n    while (elapsed() < 0.60) {\n        Params P;\n        if (iter < (int)fixed_params.size()) {\n            P = fixed_params[iter];\n        } else {\n            P.a_pot = 0.75 + 0.8 * rng.next_double();\n            P.b_deg = 20.0 + 480.0 * rng.next_double();\n            P.noise = 50.0 + 650.0 * rng.next_double();\n            P.straight = 0.0 + 240.0 * rng.next_double();\n        }\n        auto seq = build_tree_route(P, rng);\n        auto ev = evaluate_route(seq, false);\n        if (ev.score < best_score) {\n            best_score = ev.score;\n            best_seq = move(seq);\n        }\n        iter++;\n    }\n\n    // Greedy shuttle insertions.\n    vector<int> cur_seq = best_seq;\n    EvalResult cur_ev = evaluate_route(cur_seq, true);\n\n    const vector<pair<int,int>> patterns = {\n        {1, 0},\n        {2, 0}, {2, 1},\n        {3, 0}, {3, 1}, {3, 2}\n    };\n\n    for (int round = 0; round < 20 && elapsed() < 1.92; round++) {\n        if ((int)cur_seq.size() - 1 > 95000) break;\n\n        vector<int> order(Vn);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return cur_ev.contrib[a] > cur_ev.contrib[b];\n        });\n\n        int topM = min(Vn, ((int)cur_seq.size() <= 12000 ? 100 : 60));\n\n        long double local_best_score = cur_ev.score;\n        vector<int> local_best_seq;\n\n        for (int ii = 0; ii < topM && elapsed() < 1.90; ii++) {\n            int x = order[ii];\n            if (x == 0) continue;\n\n            for (int y : g[x]) {\n                for (auto [step, offset] : patterns) {\n                    auto cand = apply_shuttle(cur_seq, x, y, step, offset);\n                    if (cand.empty()) continue;\n\n                    auto ev = evaluate_route(cand, false);\n                    if (ev.score + 1e-12L < local_best_score) {\n                        local_best_score = ev.score;\n                        local_best_seq = move(cand);\n                    }\n                }\n            }\n        }\n\n        if (local_best_seq.empty()) break;\n        cur_seq = move(local_best_seq);\n        cur_ev = evaluate_route(cur_seq, true);\n    }\n\n    string ans = seq_to_moves(cur_seq);\n    cout << ans << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int INF = 1e9;\n\nstruct Solver {\n    int N, M;\n    int si, sj;\n    vector<string> board;\n    vector<string> words;\n    vector<pair<int,int>> posByChar[26];\n\n    vector<vector<int>> ov;          // overlap length [i][j] in [0,4]\n    vector<int> startApprox;         // approximate typing cost for first word\n    vector<vector<int>> edgeApprox;  // approximate typing cost to append j after i\n    vector<int> startLen;            // = 5\n    vector<vector<int>> edgeLen;     // = 5 - overlap\n\n    inline int dist(const pair<int,int>& a, const pair<int,int>& b) const {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    int overlap5(const string& a, const string& b) {\n        for (int k = 4; k >= 0; --k) {\n            bool ok = true;\n            for (int t = 0; t < k; ++t) {\n                if (a[5 - k + t] != b[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    // Exact min cost to type string s, starting with finger already on\n    // some occurrence of prevChar, with zero initial cost.\n    int cost_from_prev_char(int prevChar, const string& s) {\n        if (s.empty()) return 0;\n        const auto& initList = posByChar[prevChar];\n        vector<int> dp(initList.size(), 0), ndp;\n        const vector<pair<int,int>>* prevList = &initList;\n\n        for (char ch : s) {\n            int c = ch - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    // Exact min cost to type string s from the initial finger position.\n    int cost_from_start(const string& s) {\n        if (s.empty()) return 0;\n        int c0 = s[0] - 'A';\n        const auto& firstList = posByChar[c0];\n        vector<int> dp(firstList.size()), ndp;\n        for (int i = 0; i < (int)firstList.size(); ++i) {\n            dp[i] = abs(si - firstList[i].first) + abs(sj - firstList[i].second) + 1;\n        }\n        const vector<pair<int,int>>* prevList = &firstList;\n\n        for (int p = 1; p < (int)s.size(); ++p) {\n            int c = s[p] - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    void preprocess() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                posByChar[board[i][j] - 'A'].push_back({i, j});\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                ov[i][j] = overlap5(words[i], words[j]);\n            }\n        }\n\n        startApprox.assign(M, 0);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        startLen.assign(M, 5);\n        edgeLen.assign(M, vector<int>(M, 5));\n\n        for (int i = 0; i < M; ++i) {\n            startApprox[i] = cost_from_start(words[i]);\n        }\n\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                int r = ov[i][j];\n                string chunk = words[j].substr(r);\n                edgeApprox[i][j] = cost_from_prev_char(words[i][4] - 'A', chunk);\n                edgeLen[i][j] = 5 - r;\n            }\n        }\n    }\n\n    int insertion_delta(\n        const vector<int>& path,\n        int x, int pos,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int m = (int)path.size();\n        if (m == 0) return startC[x];\n        if (pos == 0) {\n            return startC[x] + edgeC[x][path[0]] - startC[path[0]];\n        } else if (pos == m) {\n            return edgeC[path[m - 1]][x];\n        } else {\n            return edgeC[path[pos - 1]][x] + edgeC[x][path[pos]] - edgeC[path[pos - 1]][path[pos]];\n        }\n    }\n\n    vector<int> build_order_cheapest_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        if (a == -1) {\n            path.push_back(0);\n            used[0] = 1;\n        } else {\n            path.push_back(a);\n            used[a] = 1;\n            if (b != -1) {\n                path.push_back(b);\n                used[b] = 1;\n            }\n        }\n\n        while ((int)path.size() < M) {\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n        return path;\n    }\n\n    vector<int> improve_relocate(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int n = (int)path.size();\n        for (int iter = 0; iter < 200; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (int i = 0; i < n; ++i) {\n                int x = path[i];\n\n                int remDelta = 0;\n                if (n == 1) {\n                    remDelta = 0;\n                } else if (i == 0) {\n                    int b = path[1];\n                    remDelta = startC[b] - startC[x] - edgeC[x][b];\n                } else if (i == n - 1) {\n                    int a = path[n - 2];\n                    remDelta = -edgeC[a][x];\n                } else {\n                    int a = path[i - 1];\n                    int b = path[i + 1];\n                    remDelta = edgeC[a][b] - edgeC[a][x] - edgeC[x][b];\n                }\n\n                for (int j = 0; j <= n - 1; ++j) {\n                    if (j == i) continue; // no-op\n\n                    int left = -1, right = -1;\n                    if (j < i) {\n                        left = (j == 0 ? -1 : path[j - 1]);\n                        right = path[j];\n                    } else { // j > i\n                        left = path[j];\n                        right = (j == n - 1 ? -1 : path[j + 1]);\n                    }\n\n                    int insDelta = 0;\n                    if (left == -1) {\n                        insDelta = startC[x] + edgeC[x][right] - startC[right];\n                    } else if (right == -1) {\n                        insDelta = edgeC[left][x];\n                    } else {\n                        insDelta = edgeC[left][x] + edgeC[x][right] - edgeC[left][right];\n                    }\n\n                    int delta = remDelta + insDelta;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            int x = path[bestI];\n            path.erase(path.begin() + bestI);\n            path.insert(path.begin() + bestJ, x);\n        }\n        return path;\n    }\n\n    string build_string(const vector<int>& order) {\n        string s = words[order[0]];\n        s.reserve(5 + 4 * M);\n        for (int k = 1; k < M; ++k) {\n            int i = order[k - 1];\n            int j = order[k];\n            int r = ov[i][j];\n            s += words[j].substr(r);\n        }\n        return s;\n    }\n\n    pair<int, vector<pair<int,int>>> exact_positions_for_string(const string& s) {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp, ndp;\n        const vector<pair<int,int>>* prevList = nullptr;\n\n        for (int t = 0; t < L; ++t) {\n            int c = s[t] - 'A';\n            const auto& curList = posByChar[c];\n            parent[t].assign(curList.size(), -1);\n            ndp.assign(curList.size(), INF);\n\n            if (t == 0) {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    ndp[j] = abs(si - curList[j].first) + abs(sj - curList[j].second) + 1;\n                }\n            } else {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    int best = INF, bestPrev = -1;\n                    for (int i = 0; i < (int)prevList->size(); ++i) {\n                        int cand = dp[i] + dist((*prevList)[i], curList[j]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestPrev = i;\n                        }\n                    }\n                    ndp[j] = best;\n                    parent[t][j] = bestPrev;\n                }\n            }\n\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n\n        int lastIdx = min_element(dp.begin(), dp.end()) - dp.begin();\n        int bestCost = dp[lastIdx];\n\n        vector<pair<int,int>> ops(L);\n        int idx = lastIdx;\n        for (int t = L - 1; t >= 0; --t) {\n            int c = s[t] - 'A';\n            ops[t] = posByChar[c][idx];\n            idx = parent[t][idx];\n        }\n\n        return {bestCost, ops};\n    }\n\n    void try_objective(\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps\n    ) {\n        vector<tuple<int,int,int>> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                pairs.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(pairs.begin(), pairs.end());\n\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            auto [c, a, b] = pairs[idx];\n            (void)c;\n\n            auto order = build_order_cheapest_insertion(a, b, startC, edgeC);\n            order = improve_relocate(order, startC, edgeC);\n\n            string s = build_string(order);\n            if ((int)s.size() > 5000) continue;\n\n            auto [cost, ops] = exact_positions_for_string(s);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestOps = move(ops);\n            }\n        }\n    }\n\n    void solve() {\n        preprocess();\n\n        int bestCost = INF;\n        vector<pair<int,int>> bestOps;\n\n        if (M == 1) {\n            auto res = exact_positions_for_string(words[0]);\n            bestOps = move(res.second);\n        } else {\n            // Keyboard-aware objective\n            try_objective(startApprox, edgeApprox, 20, bestCost, bestOps);\n\n            // Length-oriented objective\n            try_objective(startLen, edgeLen, 12, bestCost, bestOps);\n\n            // Also try: build by length, then polish by typing-cost objective\n            vector<tuple<int,int,int>> pairs;\n            for (int a = 0; a < M; ++a) {\n                for (int b = 0; b < M; ++b) if (a != b) {\n                    pairs.emplace_back(startLen[a] + edgeLen[a][b], a, b);\n                }\n            }\n            sort(pairs.begin(), pairs.end());\n            int use = min(12, (int)pairs.size());\n            for (int idx = 0; idx < use; ++idx) {\n                auto [c, a, b] = pairs[idx];\n                (void)c;\n                auto order = build_order_cheapest_insertion(a, b, startLen, edgeLen);\n                order = improve_relocate(order, startLen, edgeLen);\n                order = improve_relocate(order, startApprox, edgeApprox);\n\n                string s = build_string(order);\n                if ((int)s.size() > 5000) continue;\n\n                auto [cost, ops] = exact_positions_for_string(s);\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestOps = move(ops);\n                }\n            }\n        }\n\n        // Fallback (should not happen)\n        if (bestOps.empty()) {\n            string s;\n            for (auto& w : words) s += w;\n            auto [cost, ops] = exact_positions_for_string(s);\n            bestOps = move(ops);\n        }\n\n        for (auto [i, j] : bestOps) {\n            cout << i << ' ' << j << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M;\n    cin >> solver.si >> solver.sj;\n    solver.board.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.board[i];\n    solver.words.resize(solver.M);\n    for (int i = 0; i < solver.M; ++i) cin >> solver.words[i];\n\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 20;\nstatic constexpr int MAXC = 400;\nstatic constexpr int MAXQ = 56; // 2N + 16 <= 56\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct Placement {\n    vector<uint16_t> cells;              // covered board cells\n    array<uint8_t, MAXQ> contrib{};      // contribution to row/col/block features\n    vector<uint16_t> drill_ids;          // drilled-cell indices covered by this placement\n    bool valid = true;\n};\n\nstruct Field {\n    vector<pair<int,int>> shape;\n    vector<Placement> ps;\n    int valid_count = 0;\n};\n\nstruct SavedState {\n    array<short, MAXM> choice{};\n    int exact_err = INT_MAX;\n    double noisy = 1e100;\n};\n\nstruct SearchState {\n    array<short, MAXM> choice{};\n    array<int, MAXQ> feat{};\n    vector<int> pred; // predicted reserve counts on drilled cells\n    int exact_err = 0;\n    double noisy = 0.0;\n};\n\nstruct Solver {\n    int N, M;\n    double eps;\n    double alpha;\n\n    vector<Field> fields;\n    int C;\n\n    // initial aggregate features\n    int Q = 0;\n    array<double, MAXQ> estQ{};\n    array<double, MAXQ> wQ{};\n    array<int, MAXQ> qSize{};\n\n    // block partition\n    int rb[5], cb[5];\n    int block_id[MAXN][MAXN];\n    int block_area[16];\n\n    // cover list: which placements cover a cell\n    vector<vector<pair<uint8_t,uint16_t>>> coverList;\n\n    // drilled info\n    vector<int> drill_cells; // cell ids in drill order\n    vector<int> drill_obs;   // exact v(cell)\n    vector<int> cell_to_drill; // size C, -1 if not drilled\n    vector<int> exact_v;       // size C, -1 if unknown\n\n    // search scratch\n    vector<int> mark, chg, aff;\n    int iter_mark = 1;\n\n    // time\n    chrono::steady_clock::time_point st;\n\n    Solver(): C(0) {}\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool better_pair(int e1, double n1, int e2, double n2) const {\n        if (e1 != e2) return e1 < e2;\n        return n1 + 1e-12 < n2;\n    }\n\n    int ask_divination(const vector<int>& cells) {\n        cout << \"q \" << cells.size();\n        for (int id : cells) {\n            int i = id / N, j = id % N;\n            cout << ' ' << i << ' ' << j;\n        }\n        cout << endl;\n        cout.flush();\n        int y;\n        cin >> y;\n        return y;\n    }\n\n    int ask_drill(int cell) {\n        int i = cell / N, j = cell % N;\n        cout << \"q 1 \" << i << ' ' << j << endl;\n        cout.flush();\n        int v;\n        cin >> v;\n        return v;\n    }\n\n    bool ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int id : cells) {\n            int i = id / N, j = id % N;\n            cout << ' ' << i << ' ' << j;\n        }\n        cout << endl;\n        cout.flush();\n        int ok;\n        cin >> ok;\n        return ok == 1;\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        alpha = 1.0 - 2.0 * eps;\n        C = N * N;\n        fields.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int d;\n            cin >> d;\n            fields[k].shape.resize(d);\n            for (int t = 0; t < d; ++t) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].shape[t] = {i, j};\n            }\n        }\n        cell_to_drill.assign(C, -1);\n        exact_v.assign(C, -1);\n        coverList.assign(C, {});\n    }\n\n    void build_blocks() {\n        for (int t = 0; t <= 4; ++t) {\n            rb[t] = (long long)t * N / 4;\n            cb[t] = (long long)t * N / 4;\n        }\n        memset(block_area, 0, sizeof(block_area));\n        for (int i = 0; i < N; ++i) {\n            int bi = 0;\n            while (!(rb[bi] <= i && i < rb[bi+1])) ++bi;\n            for (int j = 0; j < N; ++j) {\n                int bj = 0;\n                while (!(cb[bj] <= j && j < cb[bj+1])) ++bj;\n                int b = bi * 4 + bj;\n                block_id[i][j] = b;\n                block_area[b]++;\n            }\n        }\n    }\n\n    void enumerate_placements() {\n        Q = 2 * N + 16;\n        for (int k = 0; k < M; ++k) {\n            int max_i = 0, max_j = 0;\n            for (auto [i, j] : fields[k].shape) {\n                max_i = max(max_i, i);\n                max_j = max(max_j, j);\n            }\n\n            for (int di = 0; di + max_i < N; ++di) {\n                for (int dj = 0; dj + max_j < N; ++dj) {\n                    Placement p;\n                    p.contrib.fill(0);\n                    for (auto [si, sj] : fields[k].shape) {\n                        int i = di + si;\n                        int j = dj + sj;\n                        int id = i * N + j;\n                        p.cells.push_back((uint16_t)id);\n                        p.contrib[i]++;\n                        p.contrib[N + j]++;\n                        p.contrib[2 * N + block_id[i][j]]++;\n                    }\n                    int idx = (int)fields[k].ps.size();\n                    for (int id : p.cells) {\n                        coverList[id].push_back({(uint8_t)k, (uint16_t)idx});\n                    }\n                    fields[k].ps.push_back(std::move(p));\n                }\n            }\n            fields[k].valid_count = (int)fields[k].ps.size();\n        }\n    }\n\n    void initial_queries() {\n        // rows\n        for (int i = 0; i < N; ++i) {\n            vector<int> cells;\n            cells.reserve(N);\n            for (int j = 0; j < N; ++j) cells.push_back(i * N + j);\n            int y = ask_divination(cells);\n            int k = N;\n            qSize[i] = k;\n            estQ[i] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[i] = 1.0 / var_est;\n        }\n        // cols\n        for (int j = 0; j < N; ++j) {\n            vector<int> cells;\n            cells.reserve(N);\n            for (int i = 0; i < N; ++i) cells.push_back(i * N + j);\n            int y = ask_divination(cells);\n            int qi = N + j;\n            int k = N;\n            qSize[qi] = k;\n            estQ[qi] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[qi] = 1.0 / var_est;\n        }\n        // 4x4 blocks\n        for (int bi = 0; bi < 4; ++bi) {\n            for (int bj = 0; bj < 4; ++bj) {\n                vector<int> cells;\n                for (int i = rb[bi]; i < rb[bi+1]; ++i) {\n                    for (int j = cb[bj]; j < cb[bj+1]; ++j) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                int y = ask_divination(cells);\n                int b = bi * 4 + bj;\n                int qi = 2 * N + b;\n                int k = (int)cells.size();\n                qSize[qi] = k;\n                estQ[qi] = (y - k * eps) / alpha;\n                double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n                wQ[qi] = 1.0 / var_est;\n            }\n        }\n    }\n\n    void register_drill(int cell, int v) {\n        exact_v[cell] = v;\n        if (cell_to_drill[cell] == -1) {\n            int idx = (int)drill_cells.size();\n            cell_to_drill[cell] = idx;\n            drill_cells.push_back(cell);\n            drill_obs.push_back(v);\n\n            mark.resize(drill_cells.size(), 0);\n            chg.resize(drill_cells.size(), 0);\n\n            for (auto [fk, pi] : coverList[cell]) {\n                fields[fk].ps[pi].drill_ids.push_back((uint16_t)idx);\n            }\n        } else {\n            int idx = cell_to_drill[cell];\n            drill_obs[idx] = v;\n        }\n\n        if (v == 0) {\n            for (auto [fk, pi] : coverList[cell]) {\n                auto &pl = fields[fk].ps[pi];\n                if (pl.valid) {\n                    pl.valid = false;\n                    fields[fk].valid_count--;\n                }\n            }\n        }\n    }\n\n    double initial_noisy0() const {\n        double s = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            double r = -estQ[q];\n            s += wQ[q] * r * r;\n        }\n        return s;\n    }\n\n    void calc_delta_parts(const SearchState& s, int field_idx, int newp, int &dExact, double &dNoisy) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) {\n            dExact = 0;\n            dNoisy = 0.0;\n            return;\n        }\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        dNoisy = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            dNoisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n        }\n\n        dExact = 0;\n        if (drill_cells.empty()) return;\n\n        ++iter_mark;\n        if (iter_mark == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            iter_mark = 1;\n        }\n        aff.clear();\n\n        if (oldpl) {\n            for (int id : oldpl->drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]--;\n            }\n        }\n        for (int id : newpl.drill_ids) {\n            if (mark[id] != iter_mark) {\n                mark[id] = iter_mark;\n                chg[id] = 0;\n                aff.push_back(id);\n            }\n            chg[id]++;\n        }\n\n        for (int id : aff) {\n            int oc = s.pred[id];\n            int nc = oc + chg[id];\n            int obs = drill_obs[id];\n            dExact += (nc - obs) * (nc - obs) - (oc - obs) * (oc - obs);\n        }\n    }\n\n    void apply_change(SearchState& s, int field_idx, int newp) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) return;\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            s.noisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n            s.feat[q] += d;\n        }\n\n        if (!drill_cells.empty()) {\n            ++iter_mark;\n            if (iter_mark == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                iter_mark = 1;\n            }\n            aff.clear();\n\n            if (oldpl) {\n                for (int id : oldpl->drill_ids) {\n                    if (mark[id] != iter_mark) {\n                        mark[id] = iter_mark;\n                        chg[id] = 0;\n                        aff.push_back(id);\n                    }\n                    chg[id]--;\n                }\n            }\n            for (int id : newpl.drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]++;\n            }\n\n            for (int id : aff) {\n                int oc = s.pred[id];\n                int obs = drill_obs[id];\n                s.exact_err -= (oc - obs) * (oc - obs);\n                s.pred[id] += chg[id];\n                int nc = s.pred[id];\n                s.exact_err += (nc - obs) * (nc - obs);\n            }\n        }\n\n        s.choice[field_idx] = (short)newp;\n    }\n\n    bool usable_placement(int k, int p) const {\n        if (fields[k].valid_count == 0) return true;\n        return fields[k].ps[p].valid;\n    }\n\n    SearchState greedy_random_init() {\n        SearchState s;\n        s.choice.fill(-1);\n        s.feat.fill(0);\n        s.pred.assign(drill_cells.size(), 0);\n        s.exact_err = 0;\n        for (int obs : drill_obs) s.exact_err += obs * obs;\n        s.noisy = initial_noisy0();\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n        for (int k : order) {\n            struct Cand { int p; int e; double n; };\n            Cand best[3];\n            int bsz = 0;\n\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                int de;\n                double dn;\n                calc_delta_parts(s, k, p, de, dn);\n                int ne = s.exact_err + de;\n                double nn = s.noisy + dn;\n\n                Cand cur{p, ne, nn};\n                int pos = bsz;\n                for (int t = 0; t < bsz; ++t) {\n                    if (better_pair(cur.e, cur.n, best[t].e, best[t].n)) {\n                        pos = t;\n                        break;\n                    }\n                }\n                if (pos < 3) {\n                    for (int t = min(2, bsz); t > pos; --t) best[t] = best[t-1];\n                    best[pos] = cur;\n                    if (bsz < 3) ++bsz;\n                }\n            }\n\n            if (bsz == 0) continue;\n            int pick = 0;\n            if (bsz == 2) pick = rng.next_int(0, 1);\n            else if (bsz == 3) {\n                int r = rng.next_int(0, 5);\n                if (r <= 2) pick = 0;\n                else if (r <= 4) pick = 1;\n                else pick = 2;\n            }\n            apply_change(s, k, best[pick].p);\n        }\n        return s;\n    }\n\n    void local_descent(SearchState& s, int max_sweeps = 3) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < max_sweeps; ++sw) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n            for (int k : order) {\n                int bestp = s.choice[k];\n                int beste = s.exact_err;\n                double bestn = s.noisy;\n\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (!usable_placement(k, p)) continue;\n                    int de;\n                    double dn;\n                    calc_delta_parts(s, k, p, de, dn);\n                    int ne = s.exact_err + de;\n                    double nn = s.noisy + dn;\n                    if (better_pair(ne, nn, beste, bestn)) {\n                        beste = ne;\n                        bestn = nn;\n                        bestp = p;\n                    }\n                }\n\n                if (bestp != s.choice[k]) {\n                    apply_change(s, k, bestp);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    static bool same_choice(const SavedState& a, const SavedState& b, int M) {\n        for (int i = 0; i < M; ++i) if (a.choice[i] != b.choice[i]) return false;\n        return true;\n    }\n\n    void add_saved(vector<SavedState>& top, const SearchState& s, int keep = 8) {\n        SavedState cur;\n        cur.choice = s.choice;\n        cur.exact_err = s.exact_err;\n        cur.noisy = s.noisy;\n\n        for (auto &x : top) {\n            if (same_choice(x, cur, M)) {\n                if (better_pair(cur.exact_err, cur.noisy, x.exact_err, x.noisy)) x = cur;\n                return;\n            }\n        }\n        top.push_back(cur);\n        sort(top.begin(), top.end(), [&](const SavedState& a, const SavedState& b){\n            return better_pair(a.exact_err, a.noisy, b.exact_err, b.noisy);\n        });\n        if ((int)top.size() > keep) top.resize(keep);\n    }\n\n    vector<SavedState> search_states(int restarts) {\n        vector<SavedState> top;\n        for (int it = 0; it < restarts; ++it) {\n            if (elapsed_ms() > 2500.0) break;\n            SearchState s = greedy_random_init();\n            local_descent(s, 3);\n            add_saved(top, s, 8);\n        }\n        return top;\n    }\n\n    vector<char> union_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ(C, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = choice[k];\n            if (p < 0) continue;\n            for (int id : fields[k].ps[p].cells) occ[id] = 1;\n        }\n        return occ;\n    }\n\n    vector<int> union_cells_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ = union_from_choice(choice);\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (occ[id]) ans.push_back(id);\n        return ans;\n    }\n\n    bool confident_answer(const vector<SavedState>& top, int step, int heuristic_limit, vector<int>& ans_cells) {\n        vector<int> idxs;\n        for (int i = 0; i < (int)top.size(); ++i) {\n            if (top[i].exact_err == 0) idxs.push_back(i);\n        }\n        if (idxs.empty()) return false;\n\n        int use = min(5, (int)idxs.size());\n        auto base_union = union_from_choice(top[idxs[0]].choice);\n        for (int t = 1; t < use; ++t) {\n            auto u = union_from_choice(top[idxs[t]].choice);\n            if (u != base_union) return false;\n        }\n\n        int D = (int)drill_cells.size();\n        if (use >= 3 || D >= 8 || step + 1 >= heuristic_limit || M <= 3) {\n            ans_cells.clear();\n            for (int id = 0; id < C; ++id) if (base_union[id]) ans_cells.push_back(id);\n            return true;\n        }\n        return false;\n    }\n\n    int select_drill_cell_from_states(const vector<SavedState>& top) {\n        if (!top.empty()) {\n            int best_exact = top[0].exact_err;\n            vector<int> cand_idxs;\n            for (int i = 0; i < (int)top.size(); ++i) {\n                if (top[i].exact_err == best_exact) cand_idxs.push_back(i);\n            }\n            if (cand_idxs.size() >= 2) {\n                int S = min(6, (int)cand_idxs.size());\n                vector<double> sum(C, 0.0), sq(C, 0.0), occ(C, 0.0);\n\n                for (int t = 0; t < S; ++t) {\n                    const auto& ch = top[cand_idxs[t]].choice;\n                    vector<int> cnt(C, 0);\n                    for (int k = 0; k < M; ++k) {\n                        int p = ch[k];\n                        if (p < 0) continue;\n                        for (int id : fields[k].ps[p].cells) cnt[id]++;\n                    }\n                    for (int id = 0; id < C; ++id) {\n                        if (exact_v[id] != -1) continue;\n                        sum[id] += cnt[id];\n                        sq[id] += 1.0 * cnt[id] * cnt[id];\n                        occ[id] += (cnt[id] > 0 ? 1.0 : 0.0);\n                    }\n                }\n\n                double best_score = -1.0;\n                int best_cell = -1;\n                for (int id = 0; id < C; ++id) {\n                    if (exact_v[id] != -1) continue;\n                    double mean = sum[id] / S;\n                    double var = sq[id] / S - mean * mean;\n                    double p = occ[id] / S;\n                    double score = var + 0.25 * p * (1.0 - p);\n                    if (score > best_score + 1e-12) {\n                        best_score = score;\n                        best_cell = id;\n                    }\n                }\n                if (best_cell != -1 && best_score > 1e-6) return best_cell;\n            }\n        }\n\n        // fallback: independent coverage uncertainty over valid placements\n        vector<double> var(C, 0.0), ex(C, 0.0);\n        vector<int> cnt(C, 0);\n\n        for (int k = 0; k < M; ++k) {\n            fill(cnt.begin(), cnt.end(), 0);\n            int tot = 0;\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                ++tot;\n                for (int id : fields[k].ps[p].cells) cnt[id]++;\n            }\n            if (tot == 0) continue;\n            for (int id = 0; id < C; ++id) {\n                if (exact_v[id] != -1) continue;\n                if (cnt[id] == 0) continue;\n                double p = 1.0 * cnt[id] / tot;\n                var[id] += p * (1.0 - p);\n                ex[id] += p;\n            }\n        }\n\n        double best_score = -1.0;\n        int best_cell = -1;\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1) continue;\n            double score = var[id] + 0.05 * ex[id];\n            if (score > best_score + 1e-12) {\n                best_score = score;\n                best_cell = id;\n            }\n        }\n        if (best_cell != -1) return best_cell;\n\n        for (int id = 0; id < C; ++id) if (exact_v[id] == -1) return id;\n        return -1;\n    }\n\n    bool heuristic_phase() {\n        int heuristic_limit = min(18, 6 + M / 2 + (eps < 0.08 ? 4 : 0));\n        if (M <= 3) heuristic_limit = max(heuristic_limit, 14);\n\n        bool guessed_once = false;\n\n        for (int step = 0; step < heuristic_limit; ++step) {\n            if (elapsed_ms() > 2400.0) break;\n\n            int restarts = (step == 0 ? 18 : 8);\n            if (M <= 4) restarts += 4;\n            auto top = search_states(restarts);\n\n            vector<int> ans_cells;\n            if (!guessed_once && confident_answer(top, step, heuristic_limit, ans_cells)) {\n                guessed_once = true;\n                if (ask_answer(ans_cells)) return true;\n                // failed guess -> stop heuristic, go exhaustive for safety\n                return false;\n            }\n\n            int cell = select_drill_cell_from_states(top);\n            if (cell == -1) break;\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n        return false;\n    }\n\n    void exhaustive_finish() {\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1) {\n                int v = ask_drill(id);\n                register_drill(id, v);\n            }\n        }\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        bool ok = ask_answer(ans);\n        if (!ok) {\n            // Should not happen after full drilling, but just in case:\n            exit(0);\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n        read_input();\n        build_blocks();\n        enumerate_placements();\n        initial_queries();\n\n        if (heuristic_phase()) return;\n        exhaustive_finish();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Solver {\n    int W, D, N;\n    vector<vector<int>> a;              // sorted demands per day\n    vector<vector<int>> locProf;        // sorted local profile (without hidden leftover)\n    vector<int> locRem;                 // leftover hidden in last strip\n    vector<ll> locShort;                // shortage cost for local profile\n    vector<int> globProf;               // sorted global profile\n    int globRem = 0;                    // leftover hidden in last strip\n    vector<ll> globShort;               // shortage cost per day for global profile\n\n    Solver() {\n        cin >> W >> D >> N;\n        a.assign(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    }\n\n    static ll shortage_cost_day(const vector<int>& demand, const vector<int>& prof_sorted) {\n        ll s = 0;\n        for (int k = 0; k < (int)demand.size(); k++) {\n            ll area = 1000LL * prof_sorted[k];\n            if (area < demand[k]) s += demand[k] - area;\n        }\n        return 100LL * s;\n    }\n\n    // Greedy profile for one day, under the \"full-width horizontal strips\" model.\n    // c is kept nondecreasing.\n    pair<vector<int>, int> make_local_profile(int d) {\n        vector<int> c(N, 1);\n        int rem = 1000 - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue; // keep nondecreasing\n                int deficit = a[d][k] - 1000 * c[k];\n                int gain = deficit > 0 ? min(1000, deficit) : 0;\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    // Greedy global common profile.\n    pair<vector<int>, int> make_global_profile() {\n        vector<int> c(N, 1);\n        int rem = 1000 - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int gain = 0;\n                for (int d = 0; d < D; d++) {\n                    int deficit = a[d][k] - 1000 * c[k];\n                    if (deficit > 0) gain += min(1000, deficit);\n                }\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    // Transition cost between two prefix-cut arrays.\n    ll trans_cost_pref(const int* p1, const int* p2) const {\n        int len = N - 1;\n        int i = 0, j = 0, common = 0;\n        while (i < len && j < len) {\n            if (p1[i] == p2[j]) {\n                common++;\n                i++; j++;\n            } else if (p1[i] < p2[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return 2000LL * (len - common);\n    }\n\n    // Evaluate a permutation by running DP over two states:\n    // 0 = day-specific local profile\n    // 1 = global common profile\n    ll eval_perm(const vector<int>& perm) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        ll dpL = locShort[0];\n        ll dpG = globShort[0];\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob); // local -> global on day d\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);     // global -> local on day d\n\n            ll ndpL = min(dpL + llc, dpG + glc) + locShort[d];\n            ll ndpG = min(dpL + lgc, dpG) + globShort[d];\n\n            dpL = ndpL;\n            dpG = ndpG;\n        }\n        return min(dpL, dpG);\n    }\n\n    vector<int> descend_perm(vector<int> perm) const {\n        ll cur = eval_perm(perm);\n        for (int round = 0; round < 25; round++) {\n            ll best = cur;\n            int bi = -1, bj = -1;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    swap(perm[i], perm[j]);\n                    ll sc = eval_perm(perm);\n                    swap(perm[i], perm[j]);\n                    if (sc < best) {\n                        best = sc;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n            if (bi == -1) break;\n            swap(perm[bi], perm[bj]);\n            cur = best;\n        }\n        return perm;\n    }\n\n    vector<int> choose_best_perm() {\n        vector<ll> vol(N, 0), avg(N, 0);\n        for (int k = 0; k < N; k++) {\n            for (int d = 1; d < D; d++) vol[k] += llabs(locProf[d][k] - locProf[d - 1][k]);\n            for (int d = 0; d < D; d++) avg[k] += locProf[d][k];\n        }\n\n        vector<int> id(N), rev(N), v1(N), v2(N);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        iota(v1.begin(), v1.end(), 0);\n        sort(v1.begin(), v1.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avg[x] != avg[y]) return avg[x] < avg[y];\n            return x < y;\n        });\n\n        v2 = v1;\n        reverse(v2.begin(), v2.end());\n\n        vector<vector<int>> inits = {id, rev, v1, v2};\n        // deduplicate\n        vector<vector<int>> uniq;\n        for (auto &p : inits) {\n            bool ok = true;\n            for (auto &q : uniq) if (q == p) ok = false;\n            if (ok) uniq.push_back(p);\n        }\n\n        vector<int> bestPerm = uniq[0];\n        ll bestScore = (1LL << 62);\n\n        for (auto p : uniq) {\n            p = descend_perm(p);\n            ll sc = eval_perm(p);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestPerm = p;\n            }\n        }\n        // final polishing\n        bestPerm = descend_perm(bestPerm);\n        return bestPerm;\n    }\n\n    vector<int> reconstruct_states(const vector<int>& perm) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        vector<array<ll,2>> dp(D);\n        vector<array<int,2>> par(D);\n\n        dp[0][0] = locShort[0];\n        dp[0][1] = globShort[0];\n        par[0][0] = par[0][1] = -1;\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            // to local\n            ll cand0 = dp[d - 1][0] + llc;\n            ll cand1 = dp[d - 1][1] + glc;\n            if (cand0 <= cand1) {\n                dp[d][0] = cand0 + locShort[d];\n                par[d][0] = 0;\n            } else {\n                dp[d][0] = cand1 + locShort[d];\n                par[d][0] = 1;\n            }\n\n            // to global\n            cand0 = dp[d - 1][0] + lgc;\n            cand1 = dp[d - 1][1];\n            if (cand0 <= cand1) {\n                dp[d][1] = cand0 + globShort[d];\n                par[d][1] = 0;\n            } else {\n                dp[d][1] = cand1 + globShort[d];\n                par[d][1] = 1;\n            }\n        }\n\n        vector<int> state(D);\n        state[D - 1] = (dp[D - 1][0] <= dp[D - 1][1] ? 0 : 1);\n        for (int d = D - 1; d >= 1; d--) state[d - 1] = par[d][state[d]];\n        return state;\n    }\n\n    vector<int> build_local_layout(int d, const vector<int>& perm) const {\n        vector<int> x(N);\n        for (int i = 0; i < N; i++) x[i] = locProf[d][perm[i]];\n        x[N - 1] += locRem[d]; // hidden free slack\n        return x;\n    }\n\n    vector<int> build_global_layout(const vector<int>& perm) const {\n        vector<int> x(N);\n        for (int i = 0; i < N; i++) x[i] = globProf[perm[i]];\n        x[N - 1] += globRem; // hidden free slack\n        return x;\n    }\n\n    void solve() {\n        // Local profiles\n        locProf.assign(D, vector<int>(N));\n        locRem.assign(D, 0);\n        locShort.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            auto [c, rem] = make_local_profile(d);\n            locProf[d] = c;\n            locRem[d] = rem;\n            locShort[d] = shortage_cost_day(a[d], c);\n        }\n\n        // Global profile\n        auto [gc, grem] = make_global_profile();\n        globProf = gc;\n        globRem = grem;\n        globShort.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            globShort[d] = shortage_cost_day(a[d], globProf);\n        }\n\n        // Optimize permutation of strip heights\n        vector<int> perm = choose_best_perm();\n\n        // DP over local/global layouts\n        vector<int> state = reconstruct_states(perm);\n\n        // Output rectangles\n        for (int d = 0; d < D; d++) {\n            vector<int> x = (state[d] == 0 ? build_local_layout(d, perm) : build_global_layout(perm));\n\n            vector<int> top(N), bot(N);\n            int cur = 0;\n            for (int i = 0; i < N; i++) {\n                top[i] = cur;\n                cur += x[i];\n                bot[i] = cur;\n            }\n            // should exactly fill height 1000\n            if (cur != 1000) {\n                // fallback safety (should not happen)\n                bot[N - 1] += 1000 - cur;\n            }\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            stable_sort(ord.begin(), ord.end(), [&](int i, int j) {\n                if (x[i] != x[j]) return x[i] < x[j];\n                return i < j;\n            });\n\n            // reservation k gets the k-th smallest strip by area\n            for (int k = 0; k < N; k++) {\n                int idx = ord[k];\n                cout << top[idx] << ' ' << 0 << ' ' << bot[idx] << ' ' << 1000 << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 9;\nstatic constexpr int POS = 7;              // N - 2\nstatic constexpr int MAX_A = 20 * 7 * 7;   // 980\nstatic constexpr int CELL = 81;\nstatic constexpr int MOD = 998244353;\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 Action {\n    int m, p, q;\n    array<uint8_t, 9> cell;\n    array<int, 9> val;\n};\n\nstruct Solution {\n    array<int, CELL> r{};\n    array<uint8_t, MAX_A> cnt{};\n    int L = 0;\n    long long score = 0;\n};\n\nint M_in, K_in;\narray<int, CELL> init_r;\nvector<Action> actions;\nint A = 0;\n\ninline long long gain_add(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_remove(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_swap(const Solution& s, int rem_id, int add_id) {\n    if (rem_id == add_id) return 0;\n    const auto& rm = actions[rem_id];\n    const auto& ad = actions[add_id];\n\n    long long delta = 0;\n    bool used_ad[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = rm.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv - rm.val[i];\n        if (nv < 0) nv += MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (ad.cell[j] == idx) {\n                nv += ad.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_ad[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_ad[j]) {\n            int idx = ad.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + ad.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline long long gain_add_pair(const Solution& s, int a_id, int b_id) {\n    const auto& a = actions[a_id];\n    const auto& b = actions[b_id];\n\n    long long delta = 0;\n    bool used_b[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = a.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv + a.val[i];\n        if (nv >= MOD) nv -= MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (b.cell[j] == idx) {\n                nv += b.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_b[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_b[j]) {\n            int idx = b.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + b.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline void apply_add(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    ++s.cnt[aid];\n    ++s.L;\n}\n\ninline void apply_remove(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n}\n\nSolution make_base_solution() {\n    Solution s;\n    s.r = init_r;\n    s.cnt.fill(0);\n    s.L = 0;\n    s.score = 0;\n    for (int i = 0; i < CELL; ++i) s.score += s.r[i];\n    return s;\n}\n\ntemplate <class RNG>\nSolution build_greedy(bool randomized, RNG& rng) {\n    Solution s = make_base_solution();\n\n    for (int step = 0; step < K_in; ++step) {\n        vector<pair<long long, int>> cand;\n        cand.reserve(A);\n\n        long long best_gain = LLONG_MIN;\n        int best_id = -1;\n\n        for (int aid = 0; aid < A; ++aid) {\n            long long g = gain_add(s, aid);\n            if (g > best_gain) {\n                best_gain = g;\n                best_id = aid;\n            }\n            if (g > 0) cand.push_back({g, aid});\n        }\n\n        if (best_gain <= 0) break;\n\n        int pick = best_id;\n        if (randomized) {\n            sort(cand.begin(), cand.end(), [](auto& x, auto& y) {\n                return x.first > y.first;\n            });\n            int t = min<int>(8, cand.size());\n            int total_w = t * (t + 1) / 2; // rank-biased\n            int r = (int)(rng() % total_w);\n            int acc = 0;\n            for (int i = 0; i < t; ++i) {\n                acc += (t - i);\n                if (r < acc) {\n                    pick = cand[i].second;\n                    break;\n                }\n            }\n        }\n\n        apply_add(s, pick);\n    }\n\n    return s;\n}\n\nvoid hill_climb(Solution& s, const Timer& timer, double time_limit_sec) {\n    while (timer.elapsed() < time_limit_sec) {\n        long long best_delta = 0;\n        int best_type = 0; // 1 add, 2 remove, 3 swap, 4 pair-add\n        int best_a = -1, best_b = -1;\n\n        // Add\n        if (s.L < K_in) {\n            for (int aid = 0; aid < A; ++aid) {\n                long long g = gain_add(s, aid);\n                if (g > best_delta) {\n                    best_delta = g;\n                    best_type = 1;\n                    best_a = aid;\n                }\n            }\n        }\n\n        // Remove\n        if (s.L > 0) {\n            for (int aid = 0; aid < A; ++aid) {\n                if (!s.cnt[aid]) continue;\n                long long g = gain_remove(s, aid);\n                if (g > best_delta) {\n                    best_delta = g;\n                    best_type = 2;\n                    best_a = aid;\n                }\n            }\n        }\n\n        // Swap\n        if (s.L > 0) {\n            int outer_count = 0;\n            for (int rem = 0; rem < A; ++rem) {\n                if (!s.cnt[rem]) continue;\n                for (int add = 0; add < A; ++add) {\n                    if (add == rem) continue;\n                    long long g = gain_swap(s, rem, add);\n                    if (g > best_delta) {\n                        best_delta = g;\n                        best_type = 3;\n                        best_a = rem;\n                        best_b = add;\n                    }\n                }\n                if ((++outer_count & 7) == 0 && timer.elapsed() >= time_limit_sec) break;\n            }\n        }\n\n        // Pair add\n        if (best_delta <= 0 && s.L <= K_in - 2) {\n            for (int a = 0; a < A; ++a) {\n                for (int b = a; b < A; ++b) {\n                    long long g = gain_add_pair(s, a, b);\n                    if (g > best_delta) {\n                        best_delta = g;\n                        best_type = 4;\n                        best_a = a;\n                        best_b = b;\n                    }\n                }\n                if ((a & 15) == 0 && timer.elapsed() >= time_limit_sec) break;\n            }\n        }\n\n        if (best_delta <= 0) break;\n\n        if (best_type == 1) {\n            apply_add(s, best_a);\n        } else if (best_type == 2) {\n            apply_remove(s, best_a);\n        } else if (best_type == 3) {\n            apply_remove(s, best_a);\n            apply_add(s, best_b);\n        } else if (best_type == 4) {\n            apply_add(s, best_a);\n            apply_add(s, best_b);\n        } else {\n            break;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_in;\n    cin >> N_in >> M_in >> K_in;\n\n    for (int i = 0; i < N_in; ++i) {\n        for (int j = 0; j < N_in; ++j) {\n            cin >> init_r[i * N + j];\n        }\n    }\n\n    vector<array<array<int, 3>, 3>> stamps(M_in);\n    for (int m = 0; m < M_in; ++m) {\n        for (int i = 0; i < 3; ++i) {\n            for (int j = 0; j < 3; ++j) {\n                cin >> stamps[m][i][j];\n            }\n        }\n    }\n\n    actions.clear();\n    actions.reserve(M_in * POS * POS);\n    for (int m = 0; m < M_in; ++m) {\n        for (int p = 0; p <= N_in - 3; ++p) {\n            for (int q = 0; q <= N_in - 3; ++q) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                int t = 0;\n                for (int i = 0; i < 3; ++i) {\n                    for (int j = 0; j < 3; ++j) {\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.val[t] = stamps[m][i][j];\n                        ++t;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n    A = (int)actions.size();\n\n    Timer timer;\n    const double TIME_LIMIT = 1.92;\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count() ^\n        (uint64_t)(uintptr_t)new int\n    );\n\n    Solution best = build_greedy(false, rng);\n    hill_climb(best, timer, TIME_LIMIT);\n\n    while (timer.elapsed() < TIME_LIMIT) {\n        Solution cur = build_greedy(true, rng);\n        hill_climb(cur, timer, TIME_LIMIT);\n        if (cur.score > best.score) best = cur;\n    }\n\n    vector<int> ans;\n    ans.reserve(best.L);\n    for (int aid = 0; aid < A; ++aid) {\n        for (int c = 0; c < best.cnt[aid]; ++c) {\n            ans.push_back(aid);\n        }\n    }\n\n    cout << ans.size() << '\\n';\n    for (int aid : ans) {\n        const auto& ac = actions[aid];\n        cout << ac.m << ' ' << ac.p << ' ' << ac.q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int INF = 1e9;\n\nstruct Pos {\n    int r, c;\n};\n\nstatic int mdist(const Pos& a, const Pos& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\n\n// ============================================================\n// Shared helpers\n// ============================================================\n\nstatic vector<char> make_route(Pos cur, Pos dst) {\n    vector<char> res;\n    while (cur.r < dst.r) res.push_back('D'), cur.r++;\n    while (cur.r > dst.r) res.push_back('U'), cur.r--;\n    while (cur.c < dst.c) res.push_back('R'), cur.c++;\n    while (cur.c > dst.c) res.push_back('L'), cur.c--;\n    return res;\n}\n\nstatic string macros_to_plan(const vector<pair<Pos, Pos>>& macros) {\n    string s;\n    Pos cur{0, 0};\n    for (auto [src, dst] : macros) {\n        auto p1 = make_route(cur, src);\n        for (char ch : p1) s.push_back(ch);\n        s.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) s.push_back(ch);\n        s.push_back('Q');\n        cur = dst;\n    }\n    if (s.empty()) s = \".\";\n    return s;\n}\n\n// ============================================================\n// Simple simulator to validate a produced plan\n// ============================================================\n\nstruct Simulator {\n    int A[N][N];\n\n    struct Crane {\n        int r, c;\n        int hold; // -1 if none\n        bool alive;\n        bool large;\n    };\n\n    int board[N][N];\n    int spawn_ptr[N];\n    bool dispatched[25];\n    int total_dispatched = 0;\n    Crane cranes[N];\n\n    Simulator(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n    }\n\n    bool step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (blocked) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n        return true;\n    }\n\n    bool legal_move_dest(int idx, int nr, int nc) {\n        if (nr < 0 || nr >= N || nc < 0 || nc >= N) return false;\n        if (!cranes[idx].alive) return false;\n        if (!cranes[idx].large && cranes[idx].hold != -1 && board[nr][nc] != -1) return false;\n        return true;\n    }\n\n    bool run(const string& plan0) {\n        vector<string> S(5);\n        S[0] = plan0;\n        for (int i = 1; i < 5; i++) S[i] = \"B\";\n        int T = 0;\n        for (auto &x : S) T = max(T, (int)x.size());\n\n        for (int turn = 0; turn < T; turn++) {\n            // 1. spawn\n            if (!step_spawn()) return false;\n\n            array<char, N> act;\n            for (int i = 0; i < N; i++) {\n                act[i] = (turn < (int)S[i].size() ? S[i][turn] : '.');\n            }\n\n            // Precompute intended moves for collision / passing checks\n            array<int, N> nr, nc;\n            for (int i = 0; i < N; i++) {\n                nr[i] = cranes[i].r;\n                nc[i] = cranes[i].c;\n                if (!cranes[i].alive) continue;\n                char a = act[i];\n                if (a == 'U') nr[i]--;\n                else if (a == 'D') nr[i]++;\n                else if (a == 'L') nc[i]--;\n                else if (a == 'R') nc[i]++;\n            }\n\n            // basic move legality\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) {\n                    if (act[i] != '.') return false;\n                    continue;\n                }\n                char a = act[i];\n                if (a == 'U' || a == 'D' || a == 'L' || a == 'R') {\n                    if (!legal_move_dest(i, nr[i], nc[i])) return false;\n                } else if (a == 'B') {\n                    if (cranes[i].hold != -1) return false;\n                } else if (a == 'P') {\n                    if (cranes[i].hold != -1) return false;\n                    if (board[cranes[i].r][cranes[i].c] == -1) return false;\n                } else if (a == 'Q') {\n                    if (cranes[i].hold == -1) return false;\n                    if (board[cranes[i].r][cranes[i].c] != -1) return false;\n                } else if (a == '.' ) {\n                    // ok\n                } else {\n                    return false;\n                }\n            }\n\n            // collision / passing check\n            for (int i = 0; i < N; i++) if (cranes[i].alive) {\n                for (int j = i + 1; j < N; j++) if (cranes[j].alive) {\n                    Pos pi{cranes[i].r, cranes[i].c}, pj{cranes[j].r, cranes[j].c};\n                    Pos qi{nr[i], nc[i]}, qj{nr[j], nc[j]};\n\n                    bool mi = (act[i]=='U'||act[i]=='D'||act[i]=='L'||act[i]=='R');\n                    bool mj = (act[j]=='U'||act[j]=='D'||act[j]=='L'||act[j]=='R');\n\n                    if (qi.r == qj.r && qi.c == qj.c) return false;\n                    if (mi && mj && qi.r == pj.r && qi.c == pj.c && qj.r == pi.r && qj.c == pi.c) return false;\n                }\n            }\n\n            // apply actions\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                char a = act[i];\n                if (a == '.') {\n                } else if (a == 'B') {\n                    cranes[i].alive = false;\n                } else if (a == 'P') {\n                    cranes[i].hold = board[cranes[i].r][cranes[i].c];\n                    board[cranes[i].r][cranes[i].c] = -1;\n                } else if (a == 'Q') {\n                    board[cranes[i].r][cranes[i].c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                } else {\n                    cranes[i].r = nr[i];\n                    cranes[i].c = nc[i];\n                }\n            }\n\n            // 3. dispatch\n            for (int r = 0; r < N; r++) {\n                if (board[r][4] != -1) {\n                    int b = board[r][4];\n                    board[r][4] = -1;\n                    if (b < 0 || b >= 25) return false;\n                    if (dispatched[b]) return false;\n                    dispatched[b] = true;\n                    total_dispatched++;\n                }\n            }\n        }\n\n        // allow trailing idle dispatch if any; not needed here\n        return true;\n    }\n};\n\n// ============================================================\n// Exact macro A* solver (one large crane only, exact-order only)\n// ============================================================\n\nstruct ExactSolver {\n    int A[N][N];\n    array<Pos, 15> cells; // buffer cells: columns 1..3\n    int gate_direct_lb[N][25];\n    int remsum[N][6];\n\n    ExactSolver(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        int idx = 0;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) cells[idx++] = {r, c};\n        }\n        for (int r = 0; r < N; r++) {\n            remsum[r][5] = 0;\n            for (int b = 0; b < 25; b++) {\n                int tr = b / 5;\n                gate_direct_lb[r][b] = 2 + abs(r - tr) + 4;\n            }\n            for (int p = 4; p >= 0; p--) {\n                remsum[r][p] = remsum[r][p + 1] + gate_direct_lb[r][A[r][p]];\n            }\n        }\n    }\n\n    struct Key {\n        uint64_t lo, hi;\n        bool operator==(const Key& o) const { return lo == o.lo && hi == o.hi; }\n    };\n    struct KeyHash {\n        size_t operator()(const Key& k) const {\n            uint64_t x = k.lo * 1000003ULL ^ (k.hi + 0x9e3779b97f4a7c15ULL + (k.lo<<6) + (k.lo>>2));\n            return (size_t)x;\n        }\n    };\n\n    struct Action {\n        Pos src, dst;\n    };\n\n    struct State {\n        array<uint8_t, 5> ptr{};   // next visible in each receiving row is A[r][ptr[r]]\n        array<uint8_t, 5> done{};  // dispatched count in each target row\n        array<int8_t, 15> cell{};  // -1 or container id\n        uint8_t pos = 0;           // crane position index 0..24\n        int g = INF;\n        int parent = -1;\n        Action act;\n    };\n\n    static int pos_to_idx(const Pos& p) { return p.r * 5 + p.c; }\n    static Pos idx_to_pos(int idx) { return Pos{idx / 5, idx % 5}; }\n\n    Key pack(const State& s) const {\n        __uint128_t x = 0;\n        int sh = 0;\n        auto add = [&](uint64_t v, int bits) {\n            x |= ((__uint128_t)v) << sh;\n            sh += bits;\n        };\n        for (int i = 0; i < 5; i++) add(s.ptr[i], 3);\n        for (int i = 0; i < 5; i++) add(s.done[i], 3);\n        add(s.pos, 5);\n        for (int i = 0; i < 15; i++) add((s.cell[i] == -1 ? 31 : s.cell[i]), 5);\n        uint64_t lo = (uint64_t)x;\n        uint64_t hi = (uint64_t)(x >> 64);\n        return {lo, hi};\n    }\n\n    int heuristic(const State& s) const {\n        int h = 0;\n        for (int r = 0; r < N; r++) h += remsum[r][s.ptr[r]];\n        for (int i = 0; i < 15; i++) {\n            int b = s.cell[i];\n            if (b == -1) continue;\n            int tr = b / 5;\n            h += 2 + abs(cells[i].r - tr) + (4 - cells[i].c);\n        }\n        return h;\n    }\n\n    bool finished(const State& s) const {\n        for (int t = 0; t < N; t++) if (s.done[t] != 5) return false;\n        return true;\n    }\n\n    int current_need(const State& s, int tr) const {\n        return 5 * tr + s.done[tr];\n    }\n\n    // Find exact visible \"need\" containers\n    void enumerate_dispatches(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        // check gate fronts\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= 5) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (s.done[tr] >= 5) continue;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.ptr[r]++;\n            t.done[tr]++;\n            Pos src{r, 0}, dst{tr, 4};\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n\n        // check stored cells\n        for (int i = 0; i < 15; i++) {\n            int b = s.cell[i];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (s.done[tr] >= 5) continue;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.cell[i] = -1;\n            t.done[tr]++;\n            Pos src = cells[i], dst{tr, 4};\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n    }\n\n    // store gate-front blockers into a few good buffer cells\n    void enumerate_stores(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        vector<int> empties;\n        for (int i = 0; i < 15; i++) if (s.cell[i] == -1) empties.push_back(i);\n        if (empties.empty()) return;\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= 5) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n\n            // exact-order search: don't store a currently dispatchable need\n            if (s.done[tr] < 5 && b == current_need(s, tr)) continue;\n\n            vector<pair<tuple<int,int,int>, int>> cand;\n            cand.reserve(empties.size());\n            for (int idx : empties) {\n                int sc = mdist(Pos{r,0}, cells[idx]) + mdist(cells[idx], Pos{tr,4});\n                int rowmis = abs(cells[idx].r - tr);\n                int colpref = -cells[idx].c; // closer to exit preferred\n                cand.push_back({{sc, rowmis, colpref}, idx});\n            }\n            sort(cand.begin(), cand.end());\n\n            int K = min<int>(4, cand.size());\n            for (int z = 0; z < K; z++) {\n                int idx = cand[z].second;\n                State t = s;\n                t.ptr[r]++;\n                t.cell[idx] = b;\n                Pos src{r,0}, dst = cells[idx];\n                t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n                t.pos = pos_to_idx(dst);\n                t.act = {src, dst};\n                nxt.push_back(t);\n            }\n        }\n    }\n\n    optional<string> solve_exact() {\n        auto time_begin = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - time_begin).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 15; i++) init.cell[i] = -1;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        struct PQNode {\n            int f, g, id;\n            bool operator<(const PQNode& o) const {\n                if (f != o.f) return f > o.f;\n                return g > o.g;\n            }\n        };\n\n        vector<State> states;\n        states.reserve(250000);\n        states.push_back(init);\n\n        unordered_map<Key, int, KeyHash> best;\n        best.reserve(300000);\n        best[pack(init)] = 0;\n\n        priority_queue<PQNode> pq;\n        pq.push({heuristic(init), 0, 0});\n\n        int expand_limit = 220000;\n\n        while (!pq.empty() && (int)states.size() < expand_limit && elapsed_ms() < 1400.0) {\n            auto [f, g, id] = pq.top();\n            pq.pop();\n            const State& s = states[id];\n            if (s.g != g) continue;\n\n            if (finished(s)) {\n                vector<pair<Pos, Pos>> macros;\n                int cur = id;\n                while (states[cur].parent != -1) {\n                    macros.push_back({states[cur].act.src, states[cur].act.dst});\n                    cur = states[cur].parent;\n                }\n                reverse(macros.begin(), macros.end());\n                string plan = macros_to_plan(macros);\n                return plan;\n            }\n\n            vector<State> nxt;\n            nxt.reserve(32);\n            enumerate_dispatches(s, nxt);\n            enumerate_stores(s, nxt);\n\n            for (State &t : nxt) {\n                t.parent = id;\n                Key k = pack(t);\n                auto it = best.find(k);\n                if (it != best.end()) {\n                    int old_id = it->second;\n                    if (states[old_id].g <= t.g) continue;\n                    it->second = (int)states.size();\n                } else {\n                    best.emplace(k, (int)states.size());\n                }\n                int h = heuristic(t);\n                states.push_back(t);\n                int nid = (int)states.size() - 1;\n                pq.push({t.g + h, t.g, nid});\n            }\n        }\n\n        return nullopt;\n    }\n};\n\n// ============================================================\n// Greedy fallback (safe, previous-style one-crane solver)\n// ============================================================\n\nstruct GreedyFallback {\n    int A[N][N];\n\n    int board[N][N];\n    int spawn_ptr[N];\n    bool dispatched[25];\n    int total_dispatched = 0;\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    } cranes[N];\n\n    string out[N];\n    deque<char> plan;\n\n    GreedyFallback(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n    }\n\n    int current_need(int tr) const {\n        for (int x = 5 * tr; x < 5 * tr + 5; x++) {\n            if (!dispatched[x]) return x;\n        }\n        return 5 * tr + 5;\n    }\n\n    int inversion_increase_if_dispatch_now(int b) const {\n        int tr = b / 5;\n        int cnt = 0;\n        for (int x = 5 * tr; x < b; x++) {\n            if (!dispatched[x]) cnt++;\n        }\n        return cnt;\n    }\n\n    deque<char> make_transport_plan(Pos src, Pos dst) const {\n        deque<char> q;\n        auto p1 = make_route(Pos{cranes[0].r, cranes[0].c}, src);\n        for (char ch : p1) q.push_back(ch);\n        q.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) q.push_back(ch);\n        q.push_back('Q');\n        return q;\n    }\n\n    bool is_buffer_cell_empty(int r, int c) const {\n        if (c == 4) return false;\n        if (c == 0) {\n            return spawn_ptr[r] == N && board[r][0] == -1;\n        }\n        return board[r][c] == -1;\n    }\n\n    vector<Pos> available_buffer_cells() const {\n        vector<Pos> v;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) {\n                if (board[r][c] == -1) v.push_back({r, c});\n            }\n            if (spawn_ptr[r] == N && board[r][0] == -1) v.push_back({r, 0});\n        }\n        return v;\n    }\n\n    optional<deque<char>> try_dispatch_visible_need() const {\n        struct Cand {\n            int dist;\n            Pos src, dst;\n            bool ok = false;\n        } best;\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b != current_need(tr)) continue;\n            Pos src{r, c}, dst{tr, 4};\n            int dist = mdist(Pos{cranes[0].r, cranes[0].c}, src) + mdist(src, dst);\n            if (!best.ok || dist < best.dist) best = {dist, src, dst, true};\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> try_store_blocker() const {\n        auto buf = available_buffer_cells();\n        if (buf.empty()) return nullopt;\n\n        struct Cand {\n            int gap;\n            int inv;\n            int cost;\n            Pos src, dst;\n            bool ok = false;\n        } best;\n\n        for (int r = 0; r < N; r++) {\n            if (board[r][0] == -1) continue;\n            if (spawn_ptr[r] == N) continue;\n\n            int frontPos = spawn_ptr[r] - 1;\n            int gap = INF;\n            for (int k = frontPos + 1; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                if (!dispatched[b] && b == current_need(tr)) {\n                    gap = k - frontPos;\n                    break;\n                }\n            }\n\n            int front = board[r][0];\n            int inv = inversion_increase_if_dispatch_now(front);\n\n            Pos src{r, 0};\n            int bestCost = INF;\n            Pos bestDst{-1, -1};\n            int trf = front / 5;\n            for (auto d : buf) {\n                int cost = mdist(src, d) + mdist(d, Pos{trf, 4});\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestDst = d;\n                }\n            }\n\n            Cand cur{gap, inv, bestCost, src, bestDst, true};\n            if (!best.ok || tie(cur.gap, cur.inv, cur.cost) < tie(best.gap, best.inv, best.cost)) {\n                best = cur;\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> try_forced_early_dispatch() const {\n        struct Cand {\n            int inv;\n            int dist;\n            Pos src, dst;\n            bool ok = false;\n        } best;\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n            int inv = inversion_increase_if_dispatch_now(b);\n            Pos src{r, c}, dst{tr, 4};\n            int dist = mdist(Pos{cranes[0].r, cranes[0].c}, src) + mdist(src, dst);\n            if (!best.ok || tie(inv, dist) < tie(best.inv, best.dist)) {\n                best = {inv, dist, src, dst, true};\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    deque<char> choose_next_plan() const {\n        if (auto p = try_dispatch_visible_need()) return *p;\n        if (auto p = try_store_blocker()) return *p;\n        if (auto p = try_forced_early_dispatch()) return *p;\n        return {};\n    }\n\n    void step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (blocked) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n    }\n\n    void apply_action(int idx, char act) {\n        auto &cr = cranes[idx];\n        if (!cr.alive) return;\n        if (act == '.') return;\n        if (act == 'B') {\n            cr.alive = false;\n            return;\n        }\n        if (act == 'P') {\n            cr.hold = board[cr.r][cr.c];\n            board[cr.r][cr.c] = -1;\n            return;\n        }\n        if (act == 'Q') {\n            board[cr.r][cr.c] = cr.hold;\n            cr.hold = -1;\n            return;\n        }\n        if (act == 'U') cr.r--;\n        if (act == 'D') cr.r++;\n        if (act == 'L') cr.c--;\n        if (act == 'R') cr.c++;\n    }\n\n    void step_dispatch() {\n        for (int r = 0; r < N; r++) {\n            if (board[r][4] != -1) {\n                int b = board[r][4];\n                board[r][4] = -1;\n                if (!dispatched[b]) {\n                    dispatched[b] = true;\n                    total_dispatched++;\n                }\n            }\n        }\n    }\n\n    vector<string> solve() {\n        int turn = 0;\n        while (total_dispatched < 25 && turn < 10000) {\n            step_spawn();\n\n            array<char, N> act;\n            act.fill('.');\n\n            if (turn == 0) {\n                for (int i = 1; i < N; i++) act[i] = 'B';\n            }\n\n            if (plan.empty()) plan = choose_next_plan();\n            if (!plan.empty()) {\n                act[0] = plan.front();\n                plan.pop_front();\n            }\n\n            for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n            for (int i = 0; i < N; i++) apply_action(i, act[i]);\n            step_dispatch();\n            turn++;\n        }\n\n        vector<string> res(5);\n        for (int i = 0; i < 5; i++) res[i] = out[i];\n        if (res[0].empty()) res[0] = \".\";\n        for (int i = 1; i < 5; i++) if (res[i].empty()) res[i] = \"B\";\n        return res;\n    }\n};\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A[i][j];\n\n    // 1) Try exact A* macro search\n    ExactSolver ex(A);\n    auto exact_plan = ex.solve_exact();\n    if (exact_plan.has_value()) {\n        Simulator sim(A);\n        if (sim.run(*exact_plan)) {\n            cout << *exact_plan << '\\n';\n            cout << \"B\\nB\\nB\\nB\\n\";\n            return 0;\n        }\n    }\n\n    // 2) Safe fallback\n    GreedyFallback fb(A);\n    auto ans = fb.solve();\n    for (int i = 0; i < 5; i++) cout << ans[i] << '\\n';\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Solver {\n    int N;\n    vector<vector<int>> h;\n    int M;\n\n    // ---------- Path candidate ----------\n    vector<pair<int,int>> best_path;\n    ll best_var_cost = INF64;\n    int best_type = -1; // 0=path, 1=tree\n\n    // ---------- Tree candidate ----------\n    struct TreePlan {\n        int root = -1;\n        int orient = 0; // 0: horizontal-first to root column, then vertical\n                        // 1: vertical-first to root row, then horizontal\n        vector<vector<int>> children;\n        vector<int> parent, sum, sz;\n        ll var_cost = INF64;\n    } best_tree;\n\n    Solver(int N_, vector<vector<int>> h_) : N(N_), h(move(h_)) {\n        M = N * N;\n    }\n\n    int id(int r, int c) const { return r * N + c; }\n    pair<int,int> rc(int v) const { return {v / N, v % N}; }\n\n    // =========================================================\n    // 1) Hamiltonian-cycle based one-visit path (previous idea)\n    // =========================================================\n    vector<pair<int,int>> make_canonical_cycle() {\n        // top row all, snake rows 1..N-1 excluding col 0, then go up col 0\n        vector<pair<int,int>> cyc;\n        cyc.reserve(M);\n        for (int c = 0; c < N; ++c) cyc.push_back({0, c});\n        for (int r = 1; r < N; ++r) {\n            if (r & 1) {\n                for (int c = N - 1; c >= 1; --c) cyc.push_back({r, c});\n            } else {\n                for (int c = 1; c < N; ++c) cyc.push_back({r, c});\n            }\n        }\n        for (int r = N - 1; r >= 1; --r) cyc.push_back({r, 0});\n        return cyc;\n    }\n\n    pair<int,int> transform_point(pair<int,int> p, int flip, int rot) {\n        int r = p.first, c = p.second;\n        if (flip) c = N - 1 - c;\n        for (int k = 0; k < rot; ++k) {\n            int nr = c;\n            int nc = N - 1 - r;\n            r = nr;\n            c = nc;\n        }\n        return {r, c};\n    }\n\n    void try_path_family() {\n        vector<pair<int,int>> base_cycle = make_canonical_cycle();\n        vector<vector<pair<int,int>>> cands;\n        for (int flip = 0; flip < 2; ++flip) {\n            for (int rot = 0; rot < 4; ++rot) {\n                vector<pair<int,int>> cyc;\n                cyc.reserve(M);\n                for (auto p : base_cycle) cyc.push_back(transform_point(p, flip, rot));\n                cands.push_back(cyc);\n                auto rev = cyc;\n                reverse(rev.begin(), rev.end());\n                cands.push_back(rev);\n            }\n        }\n\n        for (auto &cyc : cands) {\n            for (int s = 0; s < M; ++s) {\n                ll load = 0;\n                ll loaded_move = 0;\n                bool ok = true;\n                for (int t = 0; t < M; ++t) {\n                    auto [r, c] = cyc[(s + t) % M];\n                    load += h[r][c];\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n                    if (t + 1 < M) loaded_move += load;\n                }\n                if (!ok || load != 0) continue;\n\n                auto [sr, sc] = cyc[s];\n                ll reposition = abs(sr) + abs(sc); // empty\n                ll moves = reposition + (M - 1);\n                ll var_cost = 100LL * moves + loaded_move;\n\n                if (var_cost < best_var_cost) {\n                    best_var_cost = var_cost;\n                    best_type = 0;\n                    best_path.clear();\n                    best_path.reserve(M);\n                    for (int t = 0; t < M; ++t) best_path.push_back(cyc[(s + t) % M]);\n                }\n            }\n        }\n    }\n\n    // =========================================================\n    // 2) Cross-tree transport\n    // =========================================================\n    TreePlan build_tree_plan(int rr, int cc, int orient) {\n        TreePlan tp;\n        tp.root = id(rr, cc);\n        tp.orient = orient;\n        tp.children.assign(M, {});\n        tp.parent.assign(M, -1);\n        tp.sum.assign(M, 0);\n        tp.sz.assign(M, 1);\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                if (v == tp.root) continue;\n                int pr = r, pc = c;\n                if (orient == 0) {\n                    // horizontal-first: move toward root column, then root row\n                    if (c != cc) pc += (c < cc ? 1 : -1);\n                    else pr += (r < rr ? 1 : -1);\n                } else {\n                    // vertical-first: move toward root row, then root column\n                    if (r != rr) pr += (r < rr ? 1 : -1);\n                    else pc += (c < cc ? 1 : -1);\n                }\n                int p = id(pr, pc);\n                tp.parent[v] = p;\n                tp.children[p].push_back(v);\n            }\n        }\n\n        function<void(int)> dfs = [&](int v) {\n            auto [r, c] = rc(v);\n            tp.sum[v] = h[r][c];\n            tp.sz[v] = 1;\n            for (int u : tp.children[v]) {\n                dfs(u);\n                tp.sum[v] += tp.sum[u];\n                tp.sz[v] += tp.sz[u];\n            }\n        };\n        dfs(tp.root);\n        return tp;\n    }\n\n    struct EvalState {\n        ll load = 0;\n        ll loaded_move = 0;\n        bool ok = true;\n    };\n\n    // Greedy task selection inside a node:\n    // - among feasible negative tasks: pick one with largest (-delta)/size\n    // - otherwise among nonnegative tasks: pick one with smallest delta/size\n    // self-task has size 0 (special):\n    //   * self negative is best among feasible negatives\n    //   * self positive is worst among positives\n    int choose_task(\n        int v,\n        const TreePlan &tp,\n        const vector<int> &tasks,\n        const vector<char> &used,\n        ll cur_load\n    ) {\n        auto get_delta = [&](int tk) -> ll {\n            if (tk == -1) {\n                auto [r, c] = rc(v);\n                return h[r][c];\n            } else {\n                return tp.sum[tk];\n            }\n        };\n        auto get_sz = [&](int tk) -> int {\n            if (tk == -1) return 0;\n            return tp.sz[tk];\n        };\n\n        int best_neg = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d >= 0) continue;\n            if (cur_load < -d) continue;\n            if (best_neg == -2) {\n                best_neg = i;\n            } else {\n                ll d1 = -get_delta(tasks[i]);\n                ll d2 = -get_delta(tasks[best_neg]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_neg]);\n\n                bool better = false;\n                if (s1 == 0 && s2 == 0) better = d1 > d2;\n                else if (s1 == 0) better = true;   // self negative first\n                else if (s2 == 0) better = false;\n                else {\n                    __int128 lhs = (__int128)d1 * s2;\n                    __int128 rhs = (__int128)d2 * s1;\n                    if (lhs != rhs) better = lhs > rhs;\n                    else better = d1 > d2;\n                }\n                if (better) best_neg = i;\n            }\n        }\n        if (best_neg != -2) return best_neg;\n\n        int best_pos = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d < 0) continue;\n            if (best_pos == -2) {\n                best_pos = i;\n            } else {\n                ll p1 = get_delta(tasks[i]);\n                ll p2 = get_delta(tasks[best_pos]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_pos]);\n\n                bool better = false;\n                // zero-delta before positive-delta\n                if (p1 == 0 && p2 > 0) better = true;\n                else if (p1 > 0 && p2 == 0) better = false;\n                else if (p1 == 0 && p2 == 0) better = false;\n                else {\n                    // both positive\n                    if (s1 == 0 && s2 == 0) better = p1 < p2;\n                    else if (s1 == 0) better = false; // self positive last\n                    else if (s2 == 0) better = true;\n                    else {\n                        __int128 lhs = (__int128)p1 * s2;\n                        __int128 rhs = (__int128)p2 * s1;\n                        if (lhs != rhs) better = lhs < rhs;\n                        else better = p1 < p2;\n                    }\n                }\n                if (better) best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    void eval_tree_dfs(int v, const TreePlan &tp, EvalState &st) {\n        if (!st.ok) return;\n        vector<int> tasks = tp.children[v];\n        auto [r, c] = rc(v);\n        if (h[r][c] != 0) tasks.push_back(-1); // self task\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, st.load);\n            if (idx < 0) {\n                st.ok = false;\n                return;\n            }\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                int val = h[r][c];\n                if (val < 0 && st.load < -1LL * val) {\n                    st.ok = false;\n                    return;\n                }\n                st.load += val;\n                if (st.load < 0) {\n                    st.ok = false;\n                    return;\n                }\n            } else {\n                if (tp.sum[tk] < 0 && st.load < -1LL * tp.sum[tk]) {\n                    st.ok = false;\n                    return;\n                }\n                st.loaded_move += st.load;   // move to child\n                eval_tree_dfs(tk, tp, st);\n                if (!st.ok) return;\n                st.loaded_move += st.load;   // move back\n            }\n        }\n    }\n\n    ll eval_tree_plan(TreePlan &tp) {\n        EvalState st;\n        st.load = 0;\n        st.loaded_move = 0;\n        st.ok = true;\n        eval_tree_dfs(tp.root, tp, st);\n        if (!st.ok) return INF64;\n        if (st.load != 0) return INF64;\n        auto [rr, cc] = rc(tp.root);\n        ll reposition = abs(rr) + abs(cc);\n        ll moves = reposition + 2LL * (M - 1);\n        tp.var_cost = 100LL * moves + st.loaded_move;\n        return tp.var_cost;\n    }\n\n    void try_tree_family() {\n        for (int rr = 0; rr < N; ++rr) {\n            for (int cc = 0; cc < N; ++cc) {\n                for (int orient = 0; orient < 2; ++orient) {\n                    TreePlan tp = build_tree_plan(rr, cc, orient);\n                    ll var_cost = eval_tree_plan(tp);\n                    if (var_cost < best_var_cost) {\n                        best_var_cost = var_cost;\n                        best_type = 1;\n                        best_tree = move(tp);\n                    }\n                }\n            }\n        }\n    }\n\n    // =========================================================\n    // Output helpers\n    // =========================================================\n    vector<string> ans;\n    int cur_r = 0, cur_c = 0;\n    ll truck = 0;\n\n    void push_move_char(char ch) {\n        ans.emplace_back(1, ch);\n    }\n\n    void move_to(int tr, int tc) {\n        while (cur_r < tr) { push_move_char('D'); ++cur_r; }\n        while (cur_r > tr) { push_move_char('U'); --cur_r; }\n        while (cur_c < tc) { push_move_char('R'); ++cur_c; }\n        while (cur_c > tc) { push_move_char('L'); --cur_c; }\n    }\n\n    void move_edge(int from, int to) {\n        auto [r1, c1] = rc(from);\n        auto [r2, c2] = rc(to);\n        if (r2 == r1 + 1 && c2 == c1) push_move_char('D');\n        else if (r2 == r1 - 1 && c2 == c1) push_move_char('U');\n        else if (r2 == r1 && c2 == c1 + 1) push_move_char('R');\n        else if (r2 == r1 && c2 == c1 - 1) push_move_char('L');\n        else assert(false);\n        cur_r = r2;\n        cur_c = c2;\n    }\n\n    void output_path_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        auto [sr, sc] = best_path[0];\n        move_to(sr, sc);\n\n        for (int i = 0; i < M; ++i) {\n            auto [r, c] = best_path[i];\n            assert(cur_r == r && cur_c == c);\n\n            int v = h[r][c];\n            if (v > 0) {\n                ans.push_back(\"+\" + to_string(v));\n                truck += v;\n            } else if (v < 0) {\n                assert(truck >= -1LL * v);\n                ans.push_back(\"-\" + to_string(-v));\n                truck += v;\n            }\n            if (i + 1 < M) {\n                auto [nr, nc] = best_path[i + 1];\n                if (nr == r + 1 && nc == c) push_move_char('D');\n                else if (nr == r - 1 && nc == c) push_move_char('U');\n                else if (nr == r && nc == c + 1) push_move_char('R');\n                else if (nr == r && nc == c - 1) push_move_char('L');\n                else assert(false);\n                cur_r = nr; cur_c = nc;\n            }\n        }\n        assert(truck == 0);\n    }\n\n    void output_tree_dfs(int v, const TreePlan &tp) {\n        vector<int> tasks = tp.children[v];\n        auto [r, c] = rc(v);\n        if (h[r][c] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, truck);\n            assert(idx >= 0);\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                int val = h[r][c];\n                if (val > 0) {\n                    ans.push_back(\"+\" + to_string(val));\n                    truck += val;\n                } else if (val < 0) {\n                    assert(truck >= -1LL * val);\n                    ans.push_back(\"-\" + to_string(-val));\n                    truck += val;\n                }\n            } else {\n                move_edge(v, tk);\n                output_tree_dfs(tk, tp);\n                move_edge(tk, v);\n            }\n        }\n    }\n\n    void output_tree_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        auto [rr, cc] = rc(best_tree.root);\n        move_to(rr, cc);\n        output_tree_dfs(best_tree.root, best_tree);\n        assert(truck == 0);\n    }\n\n    void solve() {\n        try_path_family();\n        try_tree_family();\n\n        if (best_type == 0) {\n            output_path_solution();\n        } else {\n            output_tree_solution();\n        }\n\n        assert((int)ans.size() <= 100000);\n        for (auto &s : ans) cout << s << '\\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>> h(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> h[i][j];\n        }\n    }\n\n    Solver solver(N, h);\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Solver {\n    int N, M, T, S;\n    vector<vector<int>> X;\n    vector<int> V;\n\n    vector<vector<int>> neighPos;\n    vector<pair<int,int>> edgesPos;\n    vector<int> posOrder;\n    vector<int> centers;\n\n    XorShift64 rng;\n\n    void build_grid() {\n        int P = N * N;\n        neighPos.assign(P, {});\n        edgesPos.clear();\n\n        auto id = [&](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 p = id(r, c);\n                if (r + 1 < N) {\n                    int q = id(r + 1, c);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n                if (c + 1 < N) {\n                    int q = id(r, c + 1);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n            }\n        }\n\n        vector<int> ps(P);\n        iota(ps.begin(), ps.end(), 0);\n\n        auto degree = [&](int p) { return (int)neighPos[p].size(); };\n        auto dist2_center = [&](int p) {\n            int r = p / N, c = p % N;\n            double cr = (N - 1) / 2.0;\n            double cc = (N - 1) / 2.0;\n            double dr = r - cr;\n            double dc = c - cc;\n            return dr * dr + dc * dc;\n        };\n\n        sort(ps.begin(), ps.end(), [&](int a, int b) {\n            int da = degree(a), db = degree(b);\n            if (da != db) return da > db;\n            double xa = dist2_center(a), xb = dist2_center(b);\n            if (xa != xb) return xa < xb;\n            return a < b;\n        });\n        posOrder = ps;\n\n        // Central 2x2 cells for N=6, but written generally.\n        int r0 = N / 2 - 1, r1 = N / 2;\n        int c0 = N / 2 - 1, c1 = N / 2;\n        centers = {id(r0, c0), id(r0, c1), id(r1, c0), id(r1, c1)};\n    }\n\n    bool read_seed_set() {\n        X.assign(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> X[i][j])) return false;\n            }\n        }\n        return true;\n    }\n\n    struct TurnInfo {\n        vector<double> rarityW;\n        vector<double> uniqBonus;\n        vector<double> weightedScore;\n        vector<double> partnerScore; // relative to eliteMain\n        int eliteMain;\n        int eliteBestV;\n    };\n\n    TurnInfo analyze_turn(int turn) {\n        TurnInfo info;\n        info.rarityW.assign(M, 1.0);\n        info.uniqBonus.assign(S, 0.0);\n        info.weightedScore.assign(S, 0.0);\n        info.partnerScore.assign(S, 0.0);\n\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> best1(M, -1), best2(M, -1), id1(M, -1);\n\n        for (int l = 0; l < M; l++) {\n            int b1 = -1, b2 = -1, who = -1;\n            for (int i = 0; i < S; i++) {\n                int v = X[i][l];\n                if (v > b1) {\n                    b2 = b1;\n                    b1 = v;\n                    who = i;\n                } else if (v > b2) {\n                    b2 = v;\n                }\n            }\n            best1[l] = b1;\n            best2[l] = max(0, b2);\n            id1[l] = who;\n\n            int gap = best1[l] - best2[l];\n            info.uniqBonus[who] += gap;\n\n            // Rare max coordinates should matter more, but keep weights bounded.\n            info.rarityW[l] = 1.0 + min(2.5, 0.06 * gap);\n        }\n\n        for (int i = 0; i < S; i++) {\n            double ws = 0.0;\n            for (int l = 0; l < M; l++) ws += info.rarityW[l] * X[i][l];\n            info.weightedScore[i] = ws;\n        }\n\n        // Main elite: blend total value + rarity preservation + weighted quality.\n        info.eliteBestV = max_element(V.begin(), V.end()) - V.begin();\n\n        double bestEliteScore = -1e100;\n        info.eliteMain = 0;\n        double uniqCoef = 0.7 + 0.9 * explore;\n        double wcoef = 0.10 + 0.10 * explore;\n        for (int i = 0; i < S; i++) {\n            double sc = V[i] + uniqCoef * info.uniqBonus[i] + wcoef * (info.weightedScore[i] - V[i]);\n            if (sc > bestEliteScore) {\n                bestEliteScore = sc;\n                info.eliteMain = i;\n            }\n        }\n\n        int e = info.eliteMain;\n        double riskCoef = 0.25 + 0.55 * (1.0 - explore);\n\n        for (int i = 0; i < S; i++) {\n            if (i == e) {\n                info.partnerScore[i] = -1e100;\n                continue;\n            }\n            double improve = 0.0, risk = 0.0;\n            for (int l = 0; l < M; l++) {\n                int a = X[i][l];\n                int b = X[e][l];\n                if (a > b) improve += info.rarityW[l] * (a - b);\n                else if (a < b) risk += info.rarityW[l] * (b - a);\n            }\n            info.partnerScore[i] = improve - riskCoef * risk + 0.12 * V[i];\n        }\n\n        return info;\n    }\n\n    vector<int> choose_seeds(int turn, const TurnInfo& info) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        int P = N * N;\n\n        vector<char> used(S, 0);\n        vector<int> selected;\n\n        auto add_force = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Force main elite.\n        add_force(info.eliteMain);\n\n        // Force current best-by-total as well.\n        add_force(info.eliteBestV);\n\n        // Early: keep best seed of each criterion to avoid losing rare max values.\n        if (explore > 0.70) {\n            for (int l = 0; l < M; l++) {\n                int bestId = 0;\n                for (int i = 1; i < S; i++) {\n                    if (X[i][l] > X[bestId][l] ||\n                        (X[i][l] == X[bestId][l] && V[i] > V[bestId])) {\n                        bestId = i;\n                    }\n                }\n                add_force(bestId);\n            }\n        }\n\n        vector<double> candBonus(S, 0.0);\n\n        // Rankings.\n        vector<int> ordV(S), ordW(S), ordP(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        iota(ordW.begin(), ordW.end(), 0);\n        iota(ordP.begin(), ordP.end(), 0);\n\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n        sort(ordW.begin(), ordW.end(), [&](int a, int b) {\n            if (info.weightedScore[a] != info.weightedScore[b]) return info.weightedScore[a] > info.weightedScore[b];\n            return a < b;\n        });\n        sort(ordP.begin(), ordP.end(), [&](int a, int b) {\n            if (info.partnerScore[a] != info.partnerScore[b]) return info.partnerScore[a] > info.partnerScore[b];\n            return a < b;\n        });\n\n        int kTotal = 8 + (int)llround(6 * (1.0 - explore));\n        int kWeighted = 6 + (int)llround(4 * explore);\n        int kPartner = 6 + (int)llround(6 * (1.0 - explore));\n        int kCrit = (explore > 0.55 ? 2 : (explore > 0.20 ? 1 : 0));\n\n        for (int r = 0; r < min(kTotal, S); r++) candBonus[ordV[r]] += 40.0 - 2.0 * r;\n        for (int r = 0; r < min(kWeighted, S); r++) candBonus[ordW[r]] += 24.0 - 2.0 * r;\n        for (int r = 0; r < min(kPartner, S); r++) candBonus[ordP[r]] += 28.0 - 2.0 * r;\n\n        if (info.eliteMain >= 0) candBonus[info.eliteMain] += 40.0;\n        if (info.eliteBestV >= 0) candBonus[info.eliteBestV] += 20.0;\n\n        if (kCrit > 0) {\n            for (int l = 0; l < M; l++) {\n                vector<int> ids(S);\n                iota(ids.begin(), ids.end(), 0);\n                partial_sort(ids.begin(), ids.begin() + min(kCrit, S), ids.end(), [&](int a, int b) {\n                    if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                    return V[a] > V[b];\n                });\n                for (int r = 0; r < kCrit; r++) {\n                    candBonus[ids[r]] += (r == 0 ? 16.0 : 8.0) * info.rarityW[l];\n                }\n            }\n        }\n\n        vector<int> bestSel(M, 0);\n        for (int id : selected) {\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[id][l]);\n        }\n\n        double coverW = 0.65 * explore + 0.20;\n        double partnerW = 0.25 + 0.90 * (1.0 - explore);\n        double weightedExtraW = 0.10 + 0.20 * explore;\n        double uniqW = 0.15 + 0.15 * explore;\n\n        while ((int)selected.size() < P) {\n            double bestScore = -1e100;\n            int bestId = -1;\n\n            for (int i = 0; i < S; i++) if (!used[i]) {\n                double cov = 0.0;\n                for (int l = 0; l < M; l++) {\n                    if (X[i][l] > bestSel[l]) cov += info.rarityW[l] * (X[i][l] - bestSel[l]);\n                }\n\n                double sc =\n                    candBonus[i]\n                    + 1.00 * V[i]\n                    + coverW * cov\n                    + partnerW * max(0.0, info.partnerScore[i])\n                    + weightedExtraW * (info.weightedScore[i] - V[i])\n                    + uniqW * info.uniqBonus[i];\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            used[bestId] = 1;\n            selected.push_back(bestId);\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[bestId][l]);\n        }\n\n        return selected;\n    }\n\n    struct LayoutResult {\n        double score = -1e100;\n        vector<int> layoutGlobal;\n    };\n\n    double compute_pair_base(int ga, int gb, int turn) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        double mu = 0.5 * (V[ga] + V[gb]);\n\n        double sq = 0.0;\n        int diffCnt = 0;\n        int ub = 0;\n        for (int l = 0; l < M; l++) {\n            int d = X[ga][l] - X[gb][l];\n            sq += 1.0 * d * d;\n            if (d != 0) diffCnt++;\n            ub += max(X[ga][l], X[gb][l]);\n        }\n        double sigma = 0.5 * sqrt(sq);\n\n        // Immediate one-child quality approximation.\n        double q = mu + (0.55 + 0.20 * (1.0 - explore)) * sigma;\n\n        // Early turns: upper-bound potential matters more.\n        double gamma = 0.45 * explore;\n        double riskPenalty = (0.45 + 0.35 * (1.0 - explore)) * diffCnt;\n\n        return (1.0 - gamma) * q + gamma * (ub - riskPenalty);\n    }\n\n    double arrangement_score(\n        const vector<int>& perm,                  // position -> local seed\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,    // position adjacency multiplier\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        double sc = 0.0;\n        int P = N * N;\n        for (int p = 0; p < P; p++) {\n            sc += posCoef[p] * nodeVal[perm[p]];\n        }\n        for (auto [u, v] : edgesPos) {\n            sc += multMat[u][v] * pairBase[perm[u]][perm[v]];\n        }\n        return sc;\n    }\n\n    double delta_swap(\n        vector<int>& perm, int p, int q,\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        if (p == q) return 0.0;\n\n        array<pair<int,int>, 8> aff{};\n        int cnt = 0;\n\n        auto add_edge = [&](int a, int b) {\n            if (a > b) swap(a, b);\n            for (int i = 0; i < cnt; i++) {\n                if (aff[i].first == a && aff[i].second == b) return;\n            }\n            aff[cnt++] = {a, b};\n        };\n\n        for (int nb : neighPos[p]) add_edge(p, nb);\n        for (int nb : neighPos[q]) add_edge(q, nb);\n\n        double oldv = 0.0, newv = 0.0;\n\n        oldv += posCoef[p] * nodeVal[perm[p]] + posCoef[q] * nodeVal[perm[q]];\n        newv += posCoef[p] * nodeVal[perm[q]] + posCoef[q] * nodeVal[perm[p]];\n\n        auto get_seed_after = [&](int pos) -> int {\n            if (pos == p) return perm[q];\n            if (pos == q) return perm[p];\n            return perm[pos];\n        };\n\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            oldv += multMat[a][b] * pairBase[perm[a]][perm[b]];\n            newv += multMat[a][b] * pairBase[get_seed_after(a)][get_seed_after(b)];\n        }\n\n        return newv - oldv;\n    }\n\n    LayoutResult optimize_layout(const vector<int>& selected, const TurnInfo& info, int turn) {\n        int P = N * N;\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> localToGlobal = selected;\n        vector<int> globalToLocal(S, -1);\n        for (int i = 0; i < P; i++) globalToLocal[localToGlobal[i]] = i;\n\n        vector<vector<double>> pairBase(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                double w = compute_pair_base(localToGlobal[i], localToGlobal[j], turn);\n                pairBase[i][j] = pairBase[j][i] = w;\n            }\n        }\n\n        vector<double> nodeVal(P, 0.0);\n        for (int i = 0; i < P; i++) {\n            int g = localToGlobal[i];\n            nodeVal[i] =\n                0.12 * V[g]\n                + 0.18 * max(0.0, info.partnerScore[g])\n                + 0.08 * info.uniqBonus[g]\n                + 0.04 * (info.weightedScore[g] - V[g]);\n        }\n\n        vector<int> posCoef(P, 0);\n        for (int p = 0; p < P; p++) {\n            posCoef[p] = (int)neighPos[p].size() - 2; // corner 0, border 1, interior 2\n        }\n\n        vector<int> eliteCandidates;\n        if (globalToLocal[info.eliteMain] != -1) eliteCandidates.push_back(info.eliteMain);\n        if (info.eliteBestV != info.eliteMain && globalToLocal[info.eliteBestV] != -1) {\n            eliteCandidates.push_back(info.eliteBestV);\n        }\n        if (eliteCandidates.empty()) eliteCandidates.push_back(localToGlobal[0]);\n\n        LayoutResult best;\n\n        for (int eliteGlobal : eliteCandidates) {\n            int eliteLocal = globalToLocal[eliteGlobal];\n            if (eliteLocal < 0) continue;\n\n            for (int hubPos : centers) {\n                double hubBoost = 0.55 + 0.55 * (1.0 - explore);\n\n                vector<vector<double>> multMat(P, vector<double>(P, 0.0));\n                for (auto [u, v] : edgesPos) {\n                    double mul = 1.0 + ((u == hubPos || v == hubPos) ? hubBoost : 0.0);\n                    multMat[u][v] = multMat[v][u] = mul;\n                }\n\n                vector<int> perm(P, -1);\n                vector<char> usedLocal(P, 0);\n\n                perm[hubPos] = eliteLocal;\n                usedLocal[eliteLocal] = 1;\n\n                // Put good elite partners around the hub first.\n                vector<int> around = neighPos[hubPos];\n                vector<int> remSeeds;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) remSeeds.push_back(i);\n\n                sort(remSeeds.begin(), remSeeds.end(), [&](int a, int b) {\n                    int ga = localToGlobal[a], gb = localToGlobal[b];\n                    double sa =\n                        0.75 * max(0.0, info.partnerScore[ga]) +\n                        0.40 * V[ga] +\n                        0.10 * info.weightedScore[ga];\n                    double sb =\n                        0.75 * max(0.0, info.partnerScore[gb]) +\n                        0.40 * V[gb] +\n                        0.10 * info.weightedScore[gb];\n                    if (sa != sb) return sa > sb;\n                    return ga < gb;\n                });\n\n                int ptr = 0;\n                for (int p : around) {\n                    while (ptr < (int)remSeeds.size() && usedLocal[remSeeds[ptr]]) ptr++;\n                    if (ptr < (int)remSeeds.size()) {\n                        perm[p] = remSeeds[ptr];\n                        usedLocal[remSeeds[ptr]] = 1;\n                        ptr++;\n                    }\n                }\n\n                // Fill remaining positions by general node score.\n                vector<int> posFill;\n                for (int p : posOrder) {\n                    if (perm[p] == -1) posFill.push_back(p);\n                }\n\n                vector<int> seedFill;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) seedFill.push_back(i);\n\n                sort(seedFill.begin(), seedFill.end(), [&](int a, int b) {\n                    if (nodeVal[a] != nodeVal[b]) return nodeVal[a] > nodeVal[b];\n                    return localToGlobal[a] < localToGlobal[b];\n                });\n\n                for (int k = 0; k < (int)posFill.size(); k++) {\n                    perm[posFill[k]] = seedFill[k];\n                }\n\n                double cur = arrangement_score(perm, pairBase, multMat, nodeVal, posCoef);\n\n                // SA / hill-climb with elite fixed at hub.\n                vector<char> fixed(P, 0);\n                fixed[hubPos] = 1;\n\n                int ITER = 9000;\n                double T0 = 18.0;\n                double T1 = 0.15;\n\n                for (int it = 0; it < ITER; it++) {\n                    int p = rng.next_int(P);\n                    int q = rng.next_int(P);\n                    if (p == q || fixed[p] || fixed[q]) continue;\n\n                    double temp = T0 * pow(T1 / T0, (double)it / ITER);\n                    double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n\n                    if (d >= 0.0 || rng.next_double() < exp(d / temp)) {\n                        swap(perm[p], perm[q]);\n                        cur += d;\n                    }\n                }\n\n                // Final hill-climb.\n                for (int rep = 0; rep < 12; rep++) {\n                    double bestDelta = 1e-12;\n                    int bp = -1, bq = -1;\n                    for (int p = 0; p < P; p++) if (!fixed[p]) {\n                        for (int q = p + 1; q < P; q++) if (!fixed[q]) {\n                            double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n                            if (d > bestDelta) {\n                                bestDelta = d;\n                                bp = p;\n                                bq = q;\n                            }\n                        }\n                    }\n                    if (bp == -1) break;\n                    swap(perm[bp], perm[bq]);\n                    cur += bestDelta;\n                }\n\n                if (cur > best.score) {\n                    best.score = cur;\n                    best.layoutGlobal.assign(P, -1);\n                    for (int p = 0; p < P; p++) {\n                        best.layoutGlobal[p] = localToGlobal[perm[p]];\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> T;\n        S = 2 * N * (N - 1);\n\n        build_grid();\n        if (!read_seed_set()) return;\n\n        for (int turn = 0; turn < T; turn++) {\n            V.assign(S, 0);\n            for (int i = 0; i < S; i++) {\n                for (int l = 0; l < M; l++) V[i] += X[i][l];\n            }\n\n            TurnInfo info = analyze_turn(turn);\n            vector<int> selected = choose_seeds(turn, info);\n            LayoutResult res = optimize_layout(selected, info, turn);\n            vector<int> layout = res.layoutGlobal;\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    if (c) cout << ' ';\n                    cout << layout[r * N + c];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (!read_seed_set()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstatic const int DX[4] = {0, 1, 0, -1}; // R, D, L, U\nstatic const int DY[4] = {1, 0, -1, 0};\n\nstatic inline bool operator==(const Pt& a, const Pt& b) {\n    return a.x == b.x && a.y == b.y;\n}\n\nstruct Goal {\n    bool ok = false;\n    int leaf = -1;\n    int dir = -1;\n    Pt rootPos{-1, -1};\n    Pt cell{-1, -1};\n    int cost = INT_MAX;\n    int md = INT_MAX;\n    int rd = INT_MAX;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, Vmax;\n    cin >> N >> M >> Vmax;\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<Pt> surplusCells, deficitCells;\n    vector<vector<int>> sid(N, vector<int>(N, -1));\n    vector<vector<int>> did(N, vector<int>(N, -1));\n\n    long long sumx = 0, sumy = 0;\n    int cntPos = 0;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') {\n                sid[i][j] = (int)surplusCells.size();\n                surplusCells.push_back({i, j});\n                sumx += i;\n                sumy += j;\n                cntPos++;\n            }\n            if (s[i][j] == '0' && t[i][j] == '1') {\n                did[i][j] = (int)deficitCells.size();\n                deficitCells.push_back({i, j});\n                sumx += i;\n                sumy += j;\n                cntPos++;\n            }\n        }\n    }\n\n    vector<char> aliveS(surplusCells.size(), true);\n    vector<char> aliveD(deficitCells.size(), true);\n    int remS = (int)surplusCells.size();\n    int remD = (int)deficitCells.size();\n\n    int K = min(Vmax - 1, 14);\n    int R = min(4, N - 1);\n    if (R <= 0) R = 1;\n    int Vp = K + 1;\n\n    vector<int> len(Vp, 0);\n    for (int i = 1; i <= K; i++) len[i] = 1 + (i - 1) % R;\n\n    Pt initialRoot;\n    if (cntPos > 0) {\n        initialRoot.x = (int)llround((double)sumx / cntPos);\n        initialRoot.y = (int)llround((double)sumy / cntPos);\n    } else {\n        initialRoot.x = N / 2;\n        initialRoot.y = N / 2;\n    }\n    initialRoot.x = max(0, min(N - 1, initialRoot.x));\n    initialRoot.y = max(0, min(N - 1, initialRoot.y));\n\n    Pt root = initialRoot;\n\n    vector<int> dirLeaf(Vp, 0); // initially all right\n    vector<char> holding(Vp, false);\n    int holdCnt = 0;\n\n    vector<string> ops;\n\n    auto inb = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    };\n\n    auto rotDist = [&](int cur, int des) -> int {\n        int d = (des - cur + 4) % 4;\n        return min(d, 4 - d);\n    };\n\n    auto applyRot = [&](int cur, char c) -> int {\n        if (c == 'L') return (cur + 3) & 3;\n        if (c == 'R') return (cur + 1) & 3;\n        return cur;\n    };\n\n    auto oneStepRotToward = [&](int cur, int des) -> char {\n        int d = (des - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'L';\n    };\n\n    auto moveRoot = [&](Pt p, char mv) -> Pt {\n        Pt q = p;\n        if (mv == 'U') q.x--;\n        else if (mv == 'D') q.x++;\n        else if (mv == 'L') q.y--;\n        else if (mv == 'R') q.y++;\n        return q;\n    };\n\n    auto isSurplus = [&](int x, int y) -> bool {\n        int id = sid[x][y];\n        return id != -1 && aliveS[id];\n    };\n\n    auto isDeficit = [&](int x, int y) -> bool {\n        int id = did[x][y];\n        return id != -1 && aliveD[id];\n    };\n\n    auto findGoal = [&](bool wantDrop) -> Goal {\n        Goal best;\n        if (wantDrop) {\n            if (holdCnt == 0 || remD == 0) return best;\n            for (int id = 0; id < (int)deficitCells.size(); id++) {\n                if (!aliveD[id]) continue;\n                const Pt& c = deficitCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (!holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        } else {\n            if (holdCnt == K || remS == 0) return best;\n            for (int id = 0; id < (int)surplusCells.size(); id++) {\n                if (!aliveS[id]) continue;\n                const Pt& c = surplusCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        }\n        return best;\n    };\n\n    auto immediatePotential = [&](Pt newRoot, bool prioritizeDrop) -> int {\n        int drops = 0, picks = 0;\n        for (int leaf = 1; leaf <= K; leaf++) {\n            int cur = dirLeaf[leaf];\n            int candDir[3] = {cur, (cur + 3) & 3, (cur + 1) & 3};\n            if (holding[leaf]) {\n                bool ok = false;\n                for (int z = 0; z < 3 && !ok; z++) {\n                    int nd = candDir[z];\n                    int x = newRoot.x + DX[nd] * len[leaf];\n                    int y = newRoot.y + DY[nd] * len[leaf];\n                    if (inb(x, y) && isDeficit(x, y)) ok = true;\n                }\n                if (ok) drops++;\n            } else {\n                bool ok = false;\n                for (int z = 0; z < 3 && !ok; z++) {\n                    int nd = candDir[z];\n                    int x = newRoot.x + DX[nd] * len[leaf];\n                    int y = newRoot.y + DY[nd] * len[leaf];\n                    if (inb(x, y) && isSurplus(x, y)) ok = true;\n                }\n                if (ok) picks++;\n            }\n        }\n        return prioritizeDrop ? (drops * 10 + picks) : (picks * 10 + drops);\n    };\n\n    auto chooseMoveToward = [&](Pt goalPos, bool prioritizeDrop) -> char {\n        vector<char> cand;\n        if (root.x < goalPos.x) cand.push_back('D');\n        else if (root.x > goalPos.x) cand.push_back('U');\n        if (root.y < goalPos.y) cand.push_back('R');\n        else if (root.y > goalPos.y) cand.push_back('L');\n\n        if (cand.empty()) return '.';\n        if ((int)cand.size() == 1) return cand[0];\n\n        int bestScore = -1;\n        char bestMove = cand[0];\n        for (char mv : cand) {\n            Pt nr = moveRoot(root, mv);\n            int sc = immediatePotential(nr, prioritizeDrop);\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestMove = mv;\n            }\n        }\n        return bestMove;\n    };\n\n    auto appendCommand = [&](char mv, const vector<char>& rot, const vector<char>& act) {\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        for (int i = 1; i <= K; i++) {\n            cmd[i] = rot[i];\n            cmd[Vp + i] = act[i];\n        }\n        ops.push_back(cmd);\n    };\n\n    auto chooseMode = [&](const Goal& gp, const Goal& gd) -> bool {\n        if (remD == 0 && holdCnt > 0) return true;\n        if (holdCnt == 0) return false;\n        if (holdCnt == K) return true;\n        if (!gd.ok) return false;\n        if (!gp.ok) return true;\n        if (holdCnt * 2 < K) {\n            if (gd.cost + 2 < gp.cost) return true;\n            return false;\n        } else {\n            if (gp.cost + 2 < gd.cost) return false;\n            return true;\n        }\n    };\n\n    int lastActionTurn = 0;\n    const int GREEDY_MAX_TURNS = 20000;\n    const int STALL_LIMIT = 600;\n\n    while ((remD > 0 || holdCnt > 0) && (int)ops.size() < GREEDY_MAX_TURNS) {\n        Goal gp = findGoal(false);\n        Goal gd = findGoal(true);\n        if (!gp.ok && !gd.ok) break;\n\n        bool doDrop = chooseMode(gp, gd);\n        Goal goal = doDrop ? gd : gp;\n        if (!goal.ok) goal = doDrop ? gp : gd;\n        if (!goal.ok) break;\n\n        char mv = chooseMoveToward(goal.rootPos, doDrop);\n        Pt newRoot = moveRoot(root, mv);\n\n        vector<char> rot(Vp, '.');\n        vector<char> act(Vp, '.');\n\n        bool didAction = false;\n\n        // Drops first\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (!holding[leaf]) continue;\n\n            int cur = dirLeaf[leaf];\n            pair<char, int> opts[3] = {{'.', cur}, {'L', (cur + 3) & 3}, {'R', (cur + 1) & 3}};\n\n            int chosenDir = -1;\n            char chosenRot = '.';\n\n            for (int z = 0; z < 3; z++) {\n                char rc = opts[z].first;\n                int nd = opts[z].second;\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                if (!inb(x, y) || !isDeficit(x, y)) continue;\n\n                bool goalMatch = (doDrop && goal.leaf == leaf && goal.dir == nd &&\n                                  goal.rootPos == newRoot && goal.cell.x == x && goal.cell.y == y);\n                if (goalMatch) {\n                    chosenDir = nd;\n                    chosenRot = rc;\n                    break;\n                }\n                if (chosenDir == -1) {\n                    chosenDir = nd;\n                    chosenRot = rc;\n                }\n            }\n\n            if (chosenDir != -1) {\n                rot[leaf] = chosenRot;\n                act[leaf] = 'P';\n                int x = newRoot.x + DX[chosenDir] * len[leaf];\n                int y = newRoot.y + DY[chosenDir] * len[leaf];\n                int id = did[x][y];\n                if (id != -1 && aliveD[id]) {\n                    aliveD[id] = false;\n                    remD--;\n                    s[x][y] = '1';\n                    holding[leaf] = false;\n                    holdCnt--;\n                    didAction = true;\n                }\n            }\n        }\n\n        // Picks second\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (holding[leaf]) continue;\n            if (act[leaf] != '.') continue;\n\n            int cur = dirLeaf[leaf];\n            pair<char, int> opts[3] = {{'.', cur}, {'L', (cur + 3) & 3}, {'R', (cur + 1) & 3}};\n\n            int chosenDir = -1;\n            char chosenRot = '.';\n\n            for (int z = 0; z < 3; z++) {\n                char rc = opts[z].first;\n                int nd = opts[z].second;\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                if (!inb(x, y) || !isSurplus(x, y)) continue;\n\n                bool goalMatch = (!doDrop && goal.leaf == leaf && goal.dir == nd &&\n                                  goal.rootPos == newRoot && goal.cell.x == x && goal.cell.y == y);\n                if (goalMatch) {\n                    chosenDir = nd;\n                    chosenRot = rc;\n                    break;\n                }\n                if (chosenDir == -1) {\n                    chosenDir = nd;\n                    chosenRot = rc;\n                }\n            }\n\n            if (chosenDir != -1) {\n                rot[leaf] = chosenRot;\n                act[leaf] = 'P';\n                int x = newRoot.x + DX[chosenDir] * len[leaf];\n                int y = newRoot.y + DY[chosenDir] * len[leaf];\n                int id = sid[x][y];\n                if (id != -1 && aliveS[id]) {\n                    aliveS[id] = false;\n                    remS--;\n                    s[x][y] = '0';\n                    holding[leaf] = true;\n                    holdCnt++;\n                    didAction = true;\n                }\n            }\n        }\n\n        if (goal.ok && act[goal.leaf] == '.') {\n            rot[goal.leaf] = oneStepRotToward(dirLeaf[goal.leaf], goal.dir);\n        }\n\n        appendCommand(mv, rot, act);\n\n        root = newRoot;\n        for (int leaf = 1; leaf <= K; leaf++) {\n            dirLeaf[leaf] = applyRot(dirLeaf[leaf], rot[leaf]);\n        }\n\n        if (didAction) lastActionTurn = (int)ops.size();\n        if ((int)ops.size() - lastActionTurn > STALL_LIMIT) break;\n    }\n\n    auto chooseSimpleMoveToward = [&](Pt goalPos) -> char {\n        int dx = goalPos.x - root.x;\n        int dy = goalPos.y - root.y;\n        if (abs(dx) >= abs(dy)) {\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n        } else {\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n        }\n        return '.';\n    };\n\n    auto actOneGoal = [&](const Goal& g, bool wantDrop) {\n        int leaf = g.leaf;\n        while (true) {\n            char mv = chooseSimpleMoveToward(g.rootPos);\n            char rc = oneStepRotToward(dirLeaf[leaf], g.dir);\n\n            Pt nr = moveRoot(root, mv);\n            int nd = applyRot(dirLeaf[leaf], rc);\n            bool canAct = (nr == g.rootPos && nd == g.dir);\n\n            vector<char> rot(Vp, '.');\n            vector<char> act(Vp, '.');\n            rot[leaf] = rc;\n\n            if (canAct) {\n                act[leaf] = 'P';\n                int x = g.cell.x, y = g.cell.y;\n                if (wantDrop) {\n                    int id = did[x][y];\n                    if (id != -1 && aliveD[id] && holding[leaf]) {\n                        aliveD[id] = false;\n                        remD--;\n                        s[x][y] = '1';\n                        holding[leaf] = false;\n                        holdCnt--;\n                    }\n                } else {\n                    int id = sid[x][y];\n                    if (id != -1 && aliveS[id] && !holding[leaf]) {\n                        aliveS[id] = false;\n                        remS--;\n                        s[x][y] = '0';\n                        holding[leaf] = true;\n                        holdCnt++;\n                    }\n                }\n            }\n\n            appendCommand(mv, rot, act);\n            root = nr;\n            dirLeaf[leaf] = nd;\n            if (canAct) break;\n        }\n    };\n\n    while ((remD > 0 || holdCnt > 0) && (int)ops.size() < 100000) {\n        bool wantDrop = (holdCnt > 0);\n        Goal g = findGoal(wantDrop);\n        if (!g.ok) break;\n        actOneGoal(g, wantDrop);\n    }\n\n    cout << Vp << '\\n';\n    for (int i = 1; i <= K; i++) {\n        cout << 0 << ' ' << len[i] << '\\n';\n    }\n    cout << initialRoot.x << ' ' << initialRoot.y << '\\n';\n    for (const string& cmd : ops) cout << cmd << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Point {\n    int x, y;\n};\nstruct WPoint {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Candidate {\n    vector<Point> poly;\n    int approx = INT_MIN / 4;\n};\n\nstatic inline uint64_t pack_xy(int x, int y) {\n    return (uint64_t(uint32_t(x)) << 32) | uint32_t(y);\n}\n\nstatic inline bool on_segment(const Point& p, const Point& a, const Point& b) {\n    if (a.x == b.x) {\n        if (p.x != a.x) return false;\n        return min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);\n    } else if (a.y == b.y) {\n        if (p.y != a.y) return false;\n        return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x);\n    }\n    return false;\n}\n\nstatic bool inside_polygon_inclusive(const Point& p, const vector<Point>& poly) {\n    bool in = false;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        Point a = poly[i];\n        Point b = poly[(i + 1) % n];\n\n        if (on_segment(p, a, b)) return true;\n\n        // Ray casting to +x, for vertical edges only\n        if (a.x == b.x) {\n            if (a.y > b.y) swap(a, b);\n            if (a.y <= p.y && p.y < b.y && p.x < a.x) {\n                in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int exact_diff(const vector<Point>& poly, const vector<WPoint>& pts) {\n    if (poly.empty()) return INT_MIN / 4;\n\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    for (auto &q : poly) {\n        minx = min(minx, q.x);\n        maxx = max(maxx, q.x);\n        miny = min(miny, q.y);\n        maxy = max(maxy, q.y);\n    }\n\n    int diff = 0;\n    for (auto &pt : pts) {\n        if (pt.x < minx || pt.x > maxx || pt.y < miny || pt.y > maxy) continue;\n        if (inside_polygon_inclusive(Point{pt.x, pt.y}, poly)) diff += pt.w;\n    }\n    return diff;\n}\n\nstatic long long polygon_perimeter(const vector<Point>& poly) {\n    long long per = 0;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % n];\n        per += llabs((long long)a.x - b.x) + llabs((long long)a.y - b.y);\n    }\n    return per;\n}\n\nstatic vector<Point> fallback_polygon(const unordered_set<uint64_t>& occ) {\n    for (int x = 0; x <= 200; x++) {\n        for (int y = 0; y <= 200; y++) {\n            if (!occ.count(pack_xy(x, y)) &&\n                !occ.count(pack_xy(x + 1, y)) &&\n                !occ.count(pack_xy(x, y + 1)) &&\n                !occ.count(pack_xy(x + 1, y + 1))) {\n                return {\n                    {x, y},\n                    {x + 1, y},\n                    {x + 1, y + 1},\n                    {x, y + 1}\n                };\n            }\n        }\n    }\n    return {{0,0},{1,0},{1,1},{0,1}};\n}\n\nstatic vector<int> build_lines(int S, int offset) {\n    vector<int> v;\n    v.push_back(0);\n    for (int x = offset; x < 100000; x += S) {\n        if (x > 0) v.push_back(x);\n    }\n    if (v.back() != 100000) v.push_back(100000);\n    sort(v.begin(), v.end());\n    v.erase(unique(v.begin(), v.end()), v.end());\n    return v;\n}\n\nstatic int find_cell(const vector<int>& lines, int coord) {\n    int idx = int(upper_bound(lines.begin(), lines.end(), coord) - lines.begin()) - 1;\n    if (idx < 0) idx = 0;\n    if (idx >= (int)lines.size() - 1) idx = (int)lines.size() - 2;\n    return idx;\n}\n\nstatic vector<char> solve_selection_by_cut(const vector<int>& cell_w, int W, int H, int lambda) {\n    if (lambda == 0) {\n        vector<char> sel(W * H, 0);\n        for (int i = 0; i < W * H; i++) {\n            if (cell_w[i] > 0) sel[i] = 1;\n        }\n        return sel;\n    }\n\n    int SRC = W * H;\n    int SNK = W * H + 1;\n    mf_graph<int> g(W * H + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int outside_sides = 0;\n            if (x == 0) outside_sides++;\n            if (x == W - 1) outside_sides++;\n            if (y == 0) outside_sides++;\n            if (y == H - 1) outside_sides++;\n\n            int u = cell_w[v] - lambda * outside_sides;\n            if (u >= 0) g.add_edge(SRC, v, u);\n            else g.add_edge(v, SNK, -u);\n\n            if (x + 1 < W) {\n                int to = id(x + 1, y);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n            if (y + 1 < H) {\n                int to = id(x, y + 1);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n        }\n    }\n\n    g.flow(SRC, SNK);\n    auto cut = g.min_cut(SRC);\n    vector<char> sel(W * H, 0);\n    for (int i = 0; i < W * H; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nstatic void fill_holes(vector<char>& sel, int W, int H) {\n    vector<char> vis(W * H, 0);\n    queue<int> q;\n\n    auto push_if = [&](int x, int y) {\n        int id = y * W + x;\n        if (!sel[id] && !vis[id]) {\n            vis[id] = 1;\n            q.push(id);\n        }\n    };\n\n    for (int x = 0; x < W; x++) {\n        push_if(x, 0);\n        push_if(x, H - 1);\n    }\n    for (int y = 0; y < H; y++) {\n        push_if(0, y);\n        push_if(W - 1, y);\n    }\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx[d], ny = y + dy[d];\n            if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n            int nid = ny * W + nx;\n            if (!sel[nid] && !vis[nid]) {\n                vis[nid] = 1;\n                q.push(nid);\n            }\n        }\n    }\n\n    for (int i = 0; i < W * H; i++) {\n        if (!sel[i] && !vis[i]) sel[i] = 1;\n    }\n}\n\nstatic void cleanup_selection(vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int iter = 0; iter < 2; iter++) {\n        vector<char> nxt = sel;\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int id = y * W + x;\n                int cnt = 0;\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + dx[d], ny = y + dy[d];\n                    if (0 <= nx && nx < W && 0 <= ny && ny < H) {\n                        cnt += sel[ny * W + nx];\n                    }\n                }\n                if (sel[id]) {\n                    if (cnt <= 1 && cell_w[id] <= 0) nxt[id] = 0;\n                } else {\n                    if (cnt >= 3 && cell_w[id] > 0) nxt[id] = 1;\n                }\n            }\n        }\n        sel.swap(nxt);\n    }\n}\n\nstruct Component {\n    vector<int> cells;\n    int approx = 0;\n};\n\nstatic vector<Component> get_components(const vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    vector<char> vis(W * H, 0);\n    vector<Component> comps;\n    queue<int> q;\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int s = 0; s < W * H; s++) {\n        if (!sel[s] || vis[s]) continue;\n        vis[s] = 1;\n        q.push(s);\n        Component c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            c.approx += cell_w[v];\n            int x = v % W, y = v / W;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n                int nid = ny * W + nx;\n                if (sel[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        comps.push_back(move(c));\n    }\n\n    sort(comps.begin(), comps.end(), [](const Component& a, const Component& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        return a.cells.size() > b.cells.size();\n    });\n    return comps;\n}\n\nstruct PolyInfo {\n    vector<Point> poly;\n    bool ok = false;\n};\n\nstatic PolyInfo build_polygon_from_component(\n    const vector<char>& comp_sel, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    PolyInfo res;\n    int GW = W + 1;\n    int GH = H + 1;\n    int GV = GW * GH;\n    vector<int> nxt(GV, -1);\n    int edge_cnt = 0;\n\n    auto vid = [&](int x, int y) { return y * GW + x; };\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) -> bool {\n        int a = vid(x1, y1);\n        int b = vid(x2, y2);\n        if (nxt[a] != -1) return false;\n        nxt[a] = b;\n        edge_cnt++;\n        return true;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int id = y * W + x;\n            if (!comp_sel[id]) continue;\n\n            if (y == 0 || !comp_sel[(y - 1) * W + x]) {\n                if (!add_edge(x, y, x + 1, y)) return res;\n            }\n            if (x == W - 1 || !comp_sel[y * W + (x + 1)]) {\n                if (!add_edge(x + 1, y, x + 1, y + 1)) return res;\n            }\n            if (y == H - 1 || !comp_sel[(y + 1) * W + x]) {\n                if (!add_edge(x + 1, y + 1, x, y + 1)) return res;\n            }\n            if (x == 0 || !comp_sel[y * W + (x - 1)]) {\n                if (!add_edge(x, y + 1, x, y)) return res;\n            }\n        }\n    }\n\n    if (edge_cnt == 0) return res;\n\n    int start = -1;\n    for (int i = 0; i < GV; i++) {\n        if (nxt[i] != -1) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return res;\n\n    vector<int> cyc;\n    int cur = start;\n    for (int step = 0; step <= edge_cnt + 5; step++) {\n        cyc.push_back(cur);\n        cur = nxt[cur];\n        if (cur == -1) return res;\n        if (cur == start) break;\n    }\n    if (cur != start) return res;\n    if ((int)cyc.size() != edge_cnt) return res;\n\n    auto dec = [&](int v) -> pair<int,int> {\n        return {v % GW, v / GW};\n    };\n    auto dir = [&](int a, int b) -> pair<int,int> {\n        auto [x1, y1] = dec(a);\n        auto [x2, y2] = dec(b);\n        return {(x2 > x1) - (x2 < x1), (y2 > y1) - (y2 < y1)};\n    };\n\n    vector<Point> poly;\n    int n = (int)cyc.size();\n    for (int i = 0; i < n; i++) {\n        int pv = cyc[(i - 1 + n) % n];\n        int cv = cyc[i];\n        int nv = cyc[(i + 1) % n];\n        if (dir(pv, cv) != dir(cv, nv)) {\n            auto [gx, gy] = dec(cv);\n            poly.push_back({xs[gx], ys[gy]});\n        }\n    }\n\n    if ((int)poly.size() < 4) return res;\n    res.poly = move(poly);\n    res.ok = true;\n    return res;\n}\n\nstatic bool legal_polygon(const vector<Point>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    long long per = polygon_perimeter(poly);\n    if (per > 400000LL) return false;\n    for (auto &p : poly) {\n        if (p.x < 0 || p.x > 100000 || p.y < 0 || p.y > 100000) return false;\n    }\n    set<pair<int,int>> st;\n    for (auto &p : poly) {\n        if (!st.insert({p.x, p.y}).second) return false;\n    }\n    return true;\n}\n\nstatic Candidate max_sum_rectangle_candidate(\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    vector<int> acc(H);\n\n    for (int l = 0; l < W; l++) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int r = l; r < W; r++) {\n            for (int y = 0; y < H; y++) acc[y] += cell_w[y * W + r];\n\n            int cur = 0, start = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = acc[y];\n                    start = y;\n                } else {\n                    cur += acc[y];\n                }\n                if (cur > best.approx) {\n                    int x1 = xs[l], x2 = xs[r + 1];\n                    int y1 = ys[start], y2 = ys[y + 1];\n                    if (x1 < x2 && y1 < y2) {\n                        vector<Point> poly = {\n                            {x1, y1},\n                            {x2, y1},\n                            {x2, y2},\n                            {x1, y2}\n                        };\n                        if (legal_polygon(poly)) {\n                            best.approx = cur;\n                            best.poly = move(poly);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<WPoint> pts;\n    pts.reserve(2 * N);\n    unordered_set<uint64_t> occ;\n    occ.reserve(4 * N);\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, +1});\n        occ.insert(pack_xy(x, y));\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, -1});\n        occ.insert(pack_xy(x, y));\n    }\n\n    vector<Point> best_poly = fallback_polygon(occ);\n    int best_diff = exact_diff(best_poly, pts);\n\n    vector<Candidate> cands;\n\n    auto add_candidate = [&](const vector<Point>& poly, int approx) {\n        if (!legal_polygon(poly)) return;\n        cands.push_back({poly, approx});\n    };\n\n    const vector<int> sizes = {1000, 750, 500};\n\n    for (int S : sizes) {\n        vector<int> offsets = {0};\n        if (S / 2 > 0) offsets.push_back(S / 2);\n\n        vector<int> lambdas;\n        if (S >= 900) lambdas = {0, 1, 2, 4, 8, 12};\n        else if (S >= 700) lambdas = {0, 1, 2, 3, 5, 8};\n        else lambdas = {0, 1, 2, 3, 4, 6};\n\n        for (int off : offsets) {\n            vector<int> xs = build_lines(S, off);\n            vector<int> ys = build_lines(S, off);\n            int W = (int)xs.size() - 1;\n            int H = (int)ys.size() - 1;\n\n            vector<int> cell_w(W * H, 0);\n            for (auto &p : pts) {\n                int gx = find_cell(xs, p.x);\n                int gy = find_cell(ys, p.y);\n                cell_w[gy * W + gx] += p.w;\n            }\n\n            // Rectangle candidate\n            {\n                Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n                if (!rect.poly.empty()) cands.push_back(rect);\n            }\n\n            for (int lambda : lambdas) {\n                vector<char> sel = solve_selection_by_cut(cell_w, W, H, lambda);\n\n                bool any = false;\n                for (char c : sel) if (c) { any = true; break; }\n                if (!any) continue;\n\n                // base variant\n                vector<char> base = sel;\n                fill_holes(base, W, H);\n\n                // cleaned variant\n                vector<char> cleaned = base;\n                cleanup_selection(cleaned, cell_w, W, H);\n                fill_holes(cleaned, W, H);\n\n                vector<vector<char>> variants;\n                variants.push_back(base);\n                variants.push_back(cleaned);\n\n                for (auto &cur_sel : variants) {\n                    auto comps = get_components(cur_sel, cell_w, W, H);\n                    int K = min(6, (int)comps.size());\n                    for (int ci = 0; ci < K; ci++) {\n                        vector<char> comp_sel(W * H, 0);\n                        for (int v : comps[ci].cells) comp_sel[v] = 1;\n\n                        PolyInfo info = build_polygon_from_component(comp_sel, W, H, xs, ys);\n                        if (!info.ok) continue;\n                        if (!legal_polygon(info.poly)) continue;\n\n                        cands.push_back({info.poly, comps[ci].approx});\n                    }\n                }\n            }\n        }\n    }\n\n    // Sort by approximate score and evaluate exact score only for top candidates\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.poly.size() != b.poly.size()) return a.poly.size() < b.poly.size();\n        return polygon_perimeter(a.poly) < polygon_perimeter(b.poly);\n    });\n\n    // light dedup by hash\n    vector<Candidate> filtered;\n    unordered_set<uint64_t> seen;\n    seen.reserve(cands.size() * 2 + 1);\n\n    auto hash_poly = [&](const vector<Point>& poly) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (auto &p : poly) {\n            h ^= uint64_t(uint32_t(p.x)) * 1000003ULL + uint32_t(p.y);\n            h *= 1099511628211ULL;\n        }\n        h ^= poly.size();\n        return h;\n    };\n\n    for (auto &c : cands) {\n        uint64_t h = hash_poly(c.poly);\n        if (seen.insert(h).second) filtered.push_back(move(c));\n    }\n\n    int LIMIT = min(40, (int)filtered.size());\n    for (int i = 0; i < LIMIT; i++) {\n        int diff = exact_diff(filtered[i].poly, pts);\n        if (diff > best_diff) {\n            best_diff = diff;\n            best_poly = filtered[i].poly;\n        }\n    }\n\n    cout << best_poly.size() << '\\n';\n    for (auto &p : best_poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing ld = long double;\n\nstruct Op {\n    int p, r;\n    char d;\n    int b;\n};\n\nstruct Placed {\n    ll x = 0, y = 0, w = 0, h = 0;\n    bool used = false;\n};\n\nstruct Candidate {\n    ll estW = 0, estH = 0, est = 0;\n    bool isRow = true;\n    int anchorStrategy = 0;\n    vector<Op> ops;\n    string sig;\n};\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nint N, T, sigma_;\nvector<ll> obsW, obsH;\n\nbool overlap1D(ll l1, ll r1, ll l2, ll r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nvoid place_one(int p, int r, char d, int b, vector<Placed>& placed, ll& W, ll& H) {\n    ll w = (r == 0 ? obsW[p] : obsH[p]);\n    ll h = (r == 0 ? obsH[p] : obsW[p]);\n\n    ll x = 0, y = 0;\n    if (d == 'U') {\n        x = (b == -1 ? 0 : placed[b].x + placed[b].w);\n        y = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(x, x + w, placed[i].x, placed[i].x + placed[i].w)) {\n                y = max(y, placed[i].y + placed[i].h);\n            }\n        }\n    } else { // 'L'\n        y = (b == -1 ? 0 : placed[b].y + placed[b].h);\n        x = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(y, y + h, placed[i].y, placed[i].y + placed[i].h)) {\n                x = max(x, placed[i].x + placed[i].w);\n            }\n        }\n    }\n\n    placed[p] = {x, y, w, h, true};\n    W = max(W, x + w);\n    H = max(H, y + h);\n}\n\nvector<pair<int,int>> partition_strip(const vector<ll>& primary, const vector<ll>& secondary, ll cap) {\n    vector<ll> dp(N + 1, INF64);\n    vector<int> cnt(N + 1, INT_MAX);\n    vector<int> prv(N + 1, -1);\n    dp[0] = 0;\n    cnt[0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        if (dp[i] >= INF64 / 2) continue;\n        ll sumP = 0;\n        ll mxS = 0;\n        for (int j = i; j < N; j++) {\n            sumP += primary[j];\n            if (sumP > cap) break;\n            mxS = max(mxS, secondary[j]);\n\n            ll ndp = dp[i] + mxS;\n            int ncnt = cnt[i] + 1;\n            if (ndp < dp[j + 1] || (ndp == dp[j + 1] && ncnt < cnt[j + 1])) {\n                dp[j + 1] = ndp;\n                cnt[j + 1] = ncnt;\n                prv[j + 1] = i;\n            }\n        }\n    }\n\n    if (prv[N] == -1) return {};\n\n    vector<pair<int,int>> segs_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = prv[cur];\n        if (p < 0) return {};\n        segs_rev.push_back({p, cur});\n        cur = p;\n    }\n    reverse(segs_rev.begin(), segs_rev.end());\n    return segs_rev;\n}\n\nstring make_signature(bool isRow, int strategy, const vector<int>& rot, const vector<pair<int,int>>& segs) {\n    string s;\n    s.reserve(2 + N + 1 + N);\n    s.push_back(isRow ? 'R' : 'C');\n    s.push_back(char('0' + strategy));\n    for (int i = 0; i < N; i++) s.push_back(char('0' + rot[i]));\n    s.push_back('|');\n    vector<char> br(N, '0');\n    for (auto [l, r] : segs) br[r - 1] = '1';\n    for (int i = 0; i < N; i++) s.push_back(br[i]);\n    return s;\n}\n\nCandidate build_row_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy) {\n    Candidate c;\n    c.isRow = true;\n    c.anchorStrategy = strategy;\n    c.sig = make_signature(true, strategy, rot, segs);\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto bottom = [&](int idx) -> ll {\n        return placed[idx].y + placed[idx].h;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'U', -1});\n            place_one(l, rot[l], 'U', -1, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'L', b});\n            place_one(l, rot[l], 'L', b, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'U', i - 1});\n            place_one(i, rot[i], 'U', i - 1, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (bottom(i) > bottom(prevMax)) prevMax = i;\n            if (bottom(i) < bottom(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || bottom(prevMax) > bottom(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || bottom(prevMin) < bottom(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    return c;\n}\n\nCandidate build_col_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy) {\n    Candidate c;\n    c.isRow = false;\n    c.anchorStrategy = strategy;\n    c.sig = make_signature(false, strategy, rot, segs);\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto right = [&](int idx) -> ll {\n        return placed[idx].x + placed[idx].w;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'L', -1});\n            place_one(l, rot[l], 'L', -1, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'U', b});\n            place_one(l, rot[l], 'U', b, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'L', i - 1});\n            place_one(i, rot[i], 'L', i - 1, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (right(i) > right(prevMax)) prevMax = i;\n            if (right(i) < right(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || right(prevMax) > right(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || right(prevMin) < right(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    return c;\n}\n\nvector<ll> generate_caps(const vector<ll>& primary, const vector<ll>& secondary) {\n    ll total = 0, mx = 0;\n    ld area = 0;\n    for (int i = 0; i < N; i++) {\n        total += primary[i];\n        mx = max(mx, primary[i]);\n        area += (ld)primary[i] * (ld)secondary[i];\n    }\n\n    vector<ll> vals;\n    vals.push_back(mx);\n\n    static const ld mults1[] = {0.72L, 0.85L, 1.00L, 1.15L, 1.35L};\n    int K = min(N, 16);\n    for (int k = 1; k <= K; k++) {\n        ld base = (ld)total / (ld)k;\n        for (ld m : mults1) {\n            ll v = (ll)llround(base * m);\n            vals.push_back(max(mx, v));\n        }\n    }\n\n    ld sq = sqrt(area);\n    static const ld mults2[] = {0.55L, 0.70L, 0.85L, 1.00L, 1.20L, 1.45L, 1.80L};\n    for (ld m : mults2) {\n        ll v = (ll)llround(sq * m);\n        vals.push_back(max(mx, v));\n    }\n\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end()), vals.end());\n\n    // Downsample if too many.\n    if ((int)vals.size() > 40) {\n        vector<ll> sampled;\n        sampled.reserve(40);\n        for (int i = 0; i < 40; i++) {\n            int idx = (int)((ld)i * (ld)(vals.size() - 1) / 39.0L);\n            if (sampled.empty() || sampled.back() != vals[idx]) sampled.push_back(vals[idx]);\n        }\n        vals = move(sampled);\n    }\n\n    return vals;\n}\n\nvector<vector<int>> generate_rotation_modes() {\n    vector<vector<int>> modes;\n    unordered_set<string> seen;\n\n    auto add_mode = [&](const vector<int>& rot) {\n        string s;\n        s.reserve(N);\n        for (int b : rot) s.push_back(char('0' + b));\n        if (seen.insert(s).second) modes.push_back(rot);\n    };\n\n    vector<int> all0(N, 0), all1(N, 1), minW(N), minH(N);\n    for (int i = 0; i < N; i++) {\n        minW[i] = (obsW[i] <= obsH[i] ? 0 : 1);\n        minH[i] = (obsH[i] <= obsW[i] ? 0 : 1);\n    }\n\n    add_mode(all0);\n    add_mode(all1);\n    add_mode(minW);\n    add_mode(minH);\n\n    vector<ll> mxs(N);\n    for (int i = 0; i < N; i++) mxs[i] = max(obsW[i], obsH[i]);\n    vector<ll> sortedMx = mxs;\n    sort(sortedMx.begin(), sortedMx.end());\n    ll th1 = sortedMx[N / 2];\n    ll th2 = sortedMx[(3 * N) / 4];\n\n    vector<int> hy1(N), hy2(N), hy3(N);\n    for (int i = 0; i < N; i++) {\n        hy1[i] = (mxs[i] >= th1 ? minW[i] : minH[i]);\n        hy2[i] = (mxs[i] >= th2 ? minW[i] : minH[i]);\n        hy3[i] = (mxs[i] >= th1 ? minH[i] : minW[i]);\n    }\n    add_mode(hy1);\n    add_mode(hy2);\n    add_mode(hy3);\n\n    ll near_thr = 2LL * sigma_;\n    vector<vector<int>> bases = {minW, minH, hy1, hy2};\n\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int seed = 0; seed < 2; seed++) {\n            vector<int> rot = bases[bi];\n            mt19937 rng(1234567 + 1009 * bi + seed);\n            for (int i = 0; i < N; i++) {\n                if (llabs(obsW[i] - obsH[i]) <= near_thr) {\n                    if (rng() & 1) rot[i] ^= 1;\n                }\n            }\n            add_mode(rot);\n        }\n    }\n\n    return modes;\n}\n\nvector<Candidate> generate_candidates() {\n    vector<Candidate> cands;\n    unordered_set<string> usedSig;\n\n    auto add_candidate = [&](Candidate&& c) {\n        if ((int)c.ops.size() != N) return;\n        if (usedSig.insert(c.sig).second) {\n            cands.push_back(move(c));\n        }\n    };\n\n    auto rotModes = generate_rotation_modes();\n\n    for (const auto& rot : rotModes) {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = (rot[i] == 0 ? obsW[i] : obsH[i]);\n            h[i] = (rot[i] == 0 ? obsH[i] : obsW[i]);\n        }\n\n        // Row-based packings.\n        {\n            auto caps = generate_caps(w, h);\n            for (ll cap : caps) {\n                auto segs = partition_strip(w, h, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_row_candidate(segs, rot, strat));\n                }\n            }\n        }\n\n        // Column-based packings.\n        {\n            auto caps = generate_caps(h, w);\n            for (ll cap : caps) {\n                auto segs = partition_strip(h, w, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_col_candidate(segs, rot, strat));\n                }\n            }\n        }\n    }\n\n    if (cands.empty()) {\n        // Fallback: single row, original orientation.\n        vector<int> rot(N, 0);\n        vector<pair<int,int>> segs = {{0, N}};\n        add_candidate(build_row_candidate(segs, rot, 0));\n        add_candidate(build_col_candidate(segs, rot, 0));\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.est != b.est) return a.est < b.est;\n        if (a.isRow != b.isRow) return a.isRow > b.isRow;\n        return a.sig < b.sig;\n    });\n\n    return cands;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_;\n    obsW.resize(N);\n    obsH.resize(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    vector<Candidate> candidates = generate_candidates();\n    if (candidates.empty()) return 0;\n\n    vector<char> used(candidates.size(), 0);\n    int firstChosen = -1;\n\n    ld sumEstW = 0, sumEstH = 0;\n    ld sumMeasW = 0, sumMeasH = 0;\n    const ld prior = 1e6L;\n\n    auto pick_best_adjusted = [&](bool forceOppositeType, bool oppositeType) -> int {\n        ld scaleW = (sumMeasW + prior) / (sumEstW + prior);\n        ld scaleH = (sumMeasH + prior) / (sumEstH + prior);\n\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            if (forceOppositeType && candidates[i].isRow != oppositeType) continue;\n            ld sc = scaleW * (ld)candidates[i].estW + scaleH * (ld)candidates[i].estH;\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    auto pick_best_raw = [&]() -> int {\n        int best = -1;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            if (best == -1 || candidates[i].est < candidates[best].est) best = i;\n        }\n        return best;\n    };\n\n    for (int turn = 0; turn < T; turn++) {\n        int idx = -1;\n\n        if (turn == 0) {\n            idx = pick_best_raw();\n            if (idx == -1) idx = 0;\n            firstChosen = idx;\n        } else if (turn == 1 && firstChosen != -1) {\n            bool wantOpposite = !candidates[firstChosen].isRow;\n            idx = pick_best_adjusted(true, wantOpposite);\n            if (idx == -1) idx = pick_best_adjusted(false, false);\n        } else {\n            idx = pick_best_adjusted(false, false);\n        }\n\n        if (idx == -1) idx = 0;\n        used[idx] = 1;\n        const auto& cand = candidates[idx];\n\n        cout << cand.ops.size() << '\\n';\n        for (const auto& op : cand.ops) {\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        ll measW, measH;\n        if (!(cin >> measW >> measH)) return 0;\n\n        sumEstW += (ld)cand.estW;\n        sumEstH += (ld)cand.estH;\n        sumMeasW += (ld)measW;\n        sumMeasH += (ld)measH;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> X, Y, degv;\n    vector<double> rad;\n\n    mt19937 rng{712367821};\n\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    // ---------- Build/evaluate from permutation ----------\n    long long eval_perm(const vector<int>& perm, vector<int>* out_parent = nullptr) {\n        vector<int> pos(N), depth(N, 0);\n        for (int i = 0; i < N; i++) pos[perm[i]] = i;\n\n        vector<int> parent;\n        if (out_parent) parent.assign(N, -1);\n\n        long long score = 0;\n        for (int i = 0; i < N; i++) {\n            int v = perm[i];\n            int best_d = -1;\n            int best_p = -1;\n\n            for (int u : g[v]) {\n                if (pos[u] < i) {\n                    int du = depth[u];\n                    if (du >= H) continue; // child would exceed H\n                    if (du > best_d) {\n                        best_d = du;\n                        best_p = u;\n                    } else if (du == best_d && best_p != -1) {\n                        // tie-break: prefer low beauty / high degree support\n                        if (A[u] < A[best_p] ||\n                            (A[u] == A[best_p] && degv[u] > degv[best_p])) {\n                            best_p = u;\n                        }\n                    } else if (du == best_d && best_p == -1) {\n                        best_p = u;\n                    }\n                }\n            }\n\n            if (best_p == -1) {\n                depth[v] = 0;\n                if (out_parent) parent[v] = -1;\n            } else {\n                depth[v] = best_d + 1;\n                if (out_parent) parent[v] = best_p;\n            }\n            score += 1LL * (depth[v] + 1) * A[v];\n        }\n\n        if (out_parent) *out_parent = move(parent);\n        return score;\n    }\n\n    vector<int> make_perm_by_key(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_initial_perm(int mode) {\n        vector<double> key(N, 0.0);\n\n        if (mode == 0) {\n            // low beauty first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] + 1e-6 * v;\n            }\n        } else if (mode == 1) {\n            // low beauty, high degree first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] - 11.0 * degv[v] + 0.1 * rad[v];\n            }\n        } else if (mode == 2) {\n            // central low beauty support first\n            for (int v = 0; v < N; v++) {\n                key[v] = 8.0 * A[v] - 8.0 * degv[v] + 0.8 * rad[v];\n            }\n        } else if (mode == 3) {\n            // stronger centrality\n            for (int v = 0; v < N; v++) {\n                key[v] = 7.0 * A[v] - 10.0 * degv[v] + 1.5 * rad[v];\n            }\n        } else {\n            // randomized projection-based order\n            double theta = uniform_real_distribution<double>(0.0, 2.0 * acos(-1.0))(rng);\n            double c = cos(theta), s = sin(theta);\n            double wa = uniform_real_distribution<double>(5.0, 12.0)(rng);\n            double wd = uniform_real_distribution<double>(6.0, 14.0)(rng);\n            double wr = uniform_real_distribution<double>(0.0, 1.8)(rng);\n            double wp = uniform_real_distribution<double>(-0.7, 0.7)(rng);\n            for (int v = 0; v < N; v++) {\n                double proj = c * X[v] + s * Y[v];\n                key[v] = wa * A[v] - wd * degv[v] + wr * rad[v] + wp * proj + 1e-7 * v;\n            }\n        }\n        return make_perm_by_key(key);\n    }\n\n    // ---------- Permutation local search ----------\n    long long score_of_perm_cached(const vector<int>& perm) {\n        return eval_perm(perm, nullptr);\n    }\n\n    void random_insert_move(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        if (i < j) {\n            rotate(p.begin() + i, p.begin() + i + 1, p.begin() + j + 1);\n        } else {\n            rotate(p.begin() + j, p.begin() + i, p.begin() + i + 1);\n        }\n    }\n\n    void local_search_perm(vector<int>& perm, long long& best_score, double end_time) {\n        vector<int> cur = perm;\n        long long cur_score = best_score;\n\n        vector<int> best = perm;\n        long long best_local = best_score;\n\n        const double T0 = 1200.0;\n        const double T1 = 5.0;\n\n        while (elapsed() < end_time) {\n            double prog = min(1.0, elapsed() / end_time);\n            double temp = T0 * pow(T1 / T0, prog);\n\n            vector<int> cand = cur;\n            int type = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (type < 60) {\n                // insertion\n                int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                int v = cand[i];\n                int j;\n                if (A[v] >= 70 && i + 1 < N && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(i + 1, N - 1)(rng);\n                } else if (A[v] <= 30 && i > 0 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(0, i - 1)(rng);\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                }\n                random_insert_move(cand, i, j);\n            } else if (type < 90) {\n                // swap\n                int i = uniform_int_distribution<int>(0, N - 2)(rng);\n                int j;\n                if (uniform_int_distribution<int>(0, 99)(rng) < 75) {\n                    j = i + 1;\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (j == i) j = (j + 1) % N;\n                }\n                swap(cand[i], cand[j]);\n            } else {\n                // small block move\n                int l = uniform_int_distribution<int>(0, N - 1)(rng);\n                int r = uniform_int_distribution<int>(0, N - 1)(rng);\n                if (l > r) swap(l, r);\n                if (r - l >= 2) {\n                    int mid = uniform_int_distribution<int>(l + 1, r)(rng);\n                    rotate(cand.begin() + l, cand.begin() + mid, cand.begin() + r + 1);\n                }\n            }\n\n            long long sc = score_of_perm_cached(cand);\n            long long diff = sc - cur_score;\n\n            bool accept = false;\n            if (diff >= 0) {\n                accept = true;\n            } else {\n                double prob = exp((double)diff / temp);\n                double rr = uniform_real_distribution<double>(0.0, 1.0)(rng);\n                if (rr < prob) accept = true;\n            }\n\n            if (accept) {\n                cur.swap(cand);\n                cur_score = sc;\n                if (sc > best_local) {\n                    best_local = sc;\n                    best = cur;\n                }\n            }\n        }\n\n        // polish by greedy adjacent swaps\n        bool improved = true;\n        while (improved && elapsed() < end_time) {\n            improved = false;\n            for (int i = 0; i + 1 < N && elapsed() < end_time; i++) {\n                swap(best[i], best[i + 1]);\n                long long sc = score_of_perm_cached(best);\n                if (sc >= best_local) {\n                    if (sc > best_local) improved = true;\n                    best_local = sc;\n                } else {\n                    swap(best[i], best[i + 1]);\n                }\n            }\n        }\n\n        perm = move(best);\n        best_score = best_local;\n    }\n\n    // ---------- Tree improvement ----------\n    struct Info {\n        vector<int> depth, tin, tout, subH;\n        vector<long long> subA;\n        long long score = 0;\n    };\n\n    Info build_info(const vector<int>& parent) {\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) {\n            if (parent[v] != -1) ch[parent[v]].push_back(v);\n        }\n\n        Info info;\n        info.depth.assign(N, 0);\n        info.tin.assign(N, 0);\n        info.tout.assign(N, 0);\n        info.subH.assign(N, 0);\n        info.subA.assign(N, 0);\n        info.score = 0;\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v) -> void {\n            info.tin[v] = timer++;\n            info.subA[v] = A[v];\n            info.subH[v] = 0;\n            info.score += 1LL * (info.depth[v] + 1) * A[v];\n            for (int c : ch[v]) {\n                info.depth[c] = info.depth[v] + 1;\n                self(self, c);\n                info.subA[v] += info.subA[c];\n                info.subH[v] = max(info.subH[v], info.subH[c] + 1);\n            }\n            info.tout[v] = timer;\n        };\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                info.depth[v] = 0;\n                dfs(dfs, v);\n            }\n        }\n        return info;\n    }\n\n    static bool is_ancestor(const Info& info, int a, int b) {\n        return info.tin[a] <= info.tin[b] && info.tout[b] <= info.tout[a];\n    }\n\n    long long improve_tree(vector<int>& parent, double end_time) {\n        long long last_score = -1;\n\n        while (elapsed() < end_time) {\n            Info info = build_info(parent);\n            last_score = info.score;\n\n            long long best_gain = 0;\n            int best_u = -1, best_v = -1;\n            int best_nd = -1;\n            long long best_sub = -1;\n\n            auto eval_move = [&](int u, int v) {\n                // move subtree rooted at v under u\n                if (parent[v] == u) return;\n                if (is_ancestor(info, v, u)) return;\n                if (info.depth[u] >= H) return;\n\n                int nd = info.depth[u] + 1;\n                if (nd <= info.depth[v]) return;\n                if (nd + info.subH[v] > H) return;\n\n                long long gain = 1LL * (nd - info.depth[v]) * info.subA[v];\n                if (gain > best_gain ||\n                    (gain == best_gain && nd > best_nd) ||\n                    (gain == best_gain && nd == best_nd && info.subA[v] > best_sub)) {\n                    best_gain = gain;\n                    best_u = u;\n                    best_v = v;\n                    best_nd = nd;\n                    best_sub = info.subA[v];\n                }\n            };\n\n            for (auto [a, b] : edges) {\n                eval_move(a, b);\n                eval_move(b, a);\n            }\n\n            if (best_gain <= 0) break;\n            parent[best_v] = best_u;\n        }\n\n        if (last_score == -1) last_score = build_info(parent).score;\n        return last_score;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            edges[i] = {u, v};\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        X.resize(N);\n        Y.resize(N);\n        for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n        st = chrono::steady_clock::now();\n\n        degv.assign(N, 0);\n        rad.assign(N, 0.0);\n        for (int v = 0; v < N; v++) {\n            degv[v] = (int)g[v].size();\n            double dx = X[v] - 500.0;\n            double dy = Y[v] - 500.0;\n            rad[v] = sqrt(dx * dx + dy * dy);\n        }\n\n        // 1) Generate multiple initial permutations\n        vector<pair<long long, vector<int>>> cand;\n        for (int mode = 0; mode <= 3; mode++) {\n            auto p = make_initial_perm(mode);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n        while ((int)cand.size() < 14 && elapsed() < 0.20) {\n            auto p = make_initial_perm(4);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n\n        sort(cand.begin(), cand.end(), [&](auto& a, auto& b) {\n            return a.first > b.first;\n        });\n\n        // 2) Optimize top few permutations\n        long long best_perm_score = -1;\n        vector<int> best_perm;\n        int K = min<int>(3, cand.size());\n\n        double perm_search_end = 1.45;\n        for (int i = 0; i < K && elapsed() < perm_search_end; i++) {\n            vector<int> p = cand[i].second;\n            long long sc = cand[i].first;\n\n            double remaining = perm_search_end - elapsed();\n            double slice_end = elapsed() + remaining / (K - i);\n            local_search_perm(p, sc, slice_end);\n\n            if (sc > best_perm_score) {\n                best_perm_score = sc;\n                best_perm = move(p);\n            }\n        }\n\n        if (best_perm.empty()) {\n            best_perm = cand[0].second;\n            best_perm_score = cand[0].first;\n        }\n\n        // 3) Build parent from best permutation\n        vector<int> best_parent;\n        long long base_score = eval_perm(best_perm, &best_parent);\n        long long best_score = base_score;\n\n        // 4) Final tree-based monotone improvement\n        long long improved_score = improve_tree(best_parent, TL);\n        if (improved_score > best_score) best_score = improved_score;\n\n        // Output\n        for (int v = 0; v < N; v++) {\n            if (v) cout << ' ';\n            cout << best_parent[v];\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ULL;\n    XorShift(uint64_t seed = 0) {\n        x ^= seed + 0x9e3779b97f4a7c15ULL;\n        next();\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) { // [l, r]\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic constexpr int INF = 1e9;\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    vector<pair<int,int>> oni, fuku;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') oni.push_back({i, j});\n            else if (C[i][j] == 'o') fuku.push_back({i, j});\n        }\n    }\n\n    const int P = (int)oni.size();      // should be 40\n    const int F = 4 * N;                // 80\n\n    vector<int> firstRowFuku(N, N), lastRowFuku(N, -1);\n    vector<int> firstColFuku(N, N), lastColFuku(N, -1);\n\n    for (auto [i, j] : fuku) {\n        firstRowFuku[i] = min(firstRowFuku[i], j);\n        lastRowFuku[i] = max(lastRowFuku[i], j);\n        firstColFuku[j] = min(firstColFuku[j], i);\n        lastColFuku[j] = max(lastColFuku[j], i);\n    }\n\n    auto idL = [&](int i) { return i; };\n    auto idR = [&](int i) { return N + i; };\n    auto idU = [&](int j) { return 2 * N + j; };\n    auto idD = [&](int j) { return 3 * N + j; };\n\n    vector<vector<int>> depth(P, vector<int>(F, INF));\n    vector<vector<int>> opts(P);\n    vector<vector<int>> candDepths(F);\n\n    for (int p = 0; p < P; p++) {\n        auto [i, j] = oni[p];\n\n        // Left\n        if (j < firstRowFuku[i]) {\n            int f = idL(i);\n            int d = j + 1;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Right\n        if (j > lastRowFuku[i]) {\n            int f = idR(i);\n            int d = N - j;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Up\n        if (i < firstColFuku[j]) {\n            int f = idU(j);\n            int d = i + 1;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n        // Down\n        if (i > lastColFuku[j]) {\n            int f = idD(j);\n            int d = N - i;\n            depth[p][f] = d;\n            opts[p].push_back(f);\n            candDepths[f].push_back(d);\n        }\n    }\n\n    for (int f = 0; f < F; f++) {\n        auto &v = candDepths[f];\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n    }\n\n    auto calcCost = [&](const vector<int>& assign) -> int {\n        vector<int> mx(F, 0);\n        for (int p = 0; p < P; p++) {\n            int f = assign[p];\n            mx[f] = max(mx[f], depth[p][f]);\n        }\n        int s = 0;\n        for (int f = 0; f < F; f++) s += mx[f];\n        return 2 * s;\n    };\n\n    auto hillClimb = [&](vector<int> assign) -> vector<int> {\n        int cur = calcCost(assign);\n        vector<int> mx(F);\n\n        while (true) {\n            int bestCost = cur;\n            int bestG = -1, bestM = -1;\n\n            for (int g = 0; g < F; g++) {\n                if (candDepths[g].empty()) continue;\n\n                for (int M : candDepths[g]) {\n                    fill(mx.begin(), mx.end(), 0);\n\n                    for (int p = 0; p < P; p++) {\n                        int nf = assign[p];\n                        if (depth[p][g] <= M) nf = g;\n                        mx[nf] = max(mx[nf], depth[p][nf]);\n                    }\n\n                    int s = 0;\n                    for (int f = 0; f < F; f++) s += mx[f];\n                    int nc = 2 * s;\n\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestG = g;\n                        bestM = M;\n                    }\n                }\n            }\n\n            if (bestG == -1) break;\n\n            for (int p = 0; p < P; p++) {\n                if (depth[p][bestG] <= bestM) assign[p] = bestG;\n            }\n            cur = bestCost;\n        }\n\n        return assign;\n    };\n\n    auto buildInitDet = [&]() -> vector<int> {\n        vector<int> order(P);\n        iota(order.begin(), order.end(), 0);\n\n        vector<int> minDepth(P, INF);\n        for (int p = 0; p < P; p++) {\n            for (int f : opts[p]) minDepth[p] = min(minDepth[p], depth[p][f]);\n        }\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if ((int)opts[a].size() != (int)opts[b].size())\n                return opts[a].size() < opts[b].size();\n            if (minDepth[a] != minDepth[b])\n                return minDepth[a] > minDepth[b];\n            return a < b;\n        });\n\n        vector<int> curMax(F, 0), assign(P, -1);\n\n        for (int p : order) {\n            int bestF = -1;\n            tuple<int,int,int,int> bestKey = {INF, INF, INF, INF};\n            for (int f : opts[p]) {\n                int d = depth[p][f];\n                int inc = max(0, d - curMax[f]);\n                auto key = make_tuple(inc, d, curMax[f], f);\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestF = f;\n                }\n            }\n            assign[p] = bestF;\n            curMax[bestF] = max(curMax[bestF], depth[p][bestF]);\n        }\n\n        return assign;\n    };\n\n    auto buildInitRandom = [&](XorShift& rng) -> vector<int> {\n        vector<int> order(P);\n        iota(order.begin(), order.end(), 0);\n        for (int i = P - 1; i >= 1; i--) {\n            int j = rng.next_int(0, i);\n            swap(order[i], order[j]);\n        }\n\n        vector<int> curMax(F, 0), assign(P, -1);\n\n        for (int p : order) {\n            vector<tuple<int,int,int>> cand; // (inc, depth, facility)\n            for (int f : opts[p]) {\n                int d = depth[p][f];\n                int inc = max(0, d - curMax[f]);\n                cand.emplace_back(inc, d, f);\n            }\n            sort(cand.begin(), cand.end());\n\n            int chooseF;\n            if ((int)cand.size() == 1) {\n                chooseF = get<2>(cand[0]);\n            } else {\n                int k = min<int>(3, cand.size());\n                if (rng.next_int(0, 99) < 85) {\n                    // weighted among top k: k, k-1, ...\n                    int total = k * (k + 1) / 2;\n                    int x = rng.next_int(1, total);\n                    int acc = 0, pick = 0;\n                    for (int t = 0; t < k; t++) {\n                        acc += (k - t);\n                        if (x <= acc) {\n                            pick = t;\n                            break;\n                        }\n                    }\n                    chooseF = get<2>(cand[pick]);\n                } else {\n                    chooseF = get<2>(cand[rng.next_int(0, (int)cand.size() - 1)]);\n                }\n            }\n\n            assign[p] = chooseF;\n            curMax[chooseF] = max(curMax[chooseF], depth[p][chooseF]);\n        }\n\n        return assign;\n    };\n\n    auto perturb = [&](const vector<int>& base, XorShift& rng) -> vector<int> {\n        vector<int> a = base;\n        int changes = rng.next_int(1, 6);\n        for (int t = 0; t < changes; t++) {\n            int p = rng.next_int(0, P - 1);\n            int idx = rng.next_int(0, (int)opts[p].size() - 1);\n            a[p] = opts[p][idx];\n        }\n        return a;\n    };\n\n    uint64_t seed = 0;\n    for (auto &row : C) {\n        for (char ch : row) seed = seed * 131 + ch;\n    }\n    XorShift rng(seed ^ 0x123456789abcdefULL);\n\n    auto start = chrono::steady_clock::now();\n    auto deadline = start + chrono::milliseconds(1850);\n\n    vector<int> bestAssign = hillClimb(buildInitDet());\n    int bestCost = calcCost(bestAssign);\n\n    int iter = 0;\n    while (chrono::steady_clock::now() < deadline) {\n        vector<int> init;\n        if (iter < 20) {\n            init = buildInitRandom(rng);\n        } else if (iter % 3 == 0) {\n            init = perturb(bestAssign, rng);\n        } else {\n            init = buildInitRandom(rng);\n        }\n\n        auto sol = hillClimb(init);\n        int cost = calcCost(sol);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestAssign = std::move(sol);\n        }\n        iter++;\n    }\n\n    vector<int> maxDepth(F, 0);\n    for (int p = 0; p < P; p++) {\n        int f = bestAssign[p];\n        maxDepth[f] = max(maxDepth[f], depth[p][f]);\n    }\n\n    vector<pair<char,int>> ans;\n    ans.reserve(bestCost);\n\n    for (int f = 0; f < F; f++) {\n        int k = maxDepth[f];\n        if (k == 0) continue;\n\n        if (f < N) {\n            int i = f;\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n        } else if (f < 2 * N) {\n            int i = f - N;\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n        } else if (f < 3 * N) {\n            int j = f - 2 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n        } else {\n            int j = f - 3 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n        }\n    }\n\n    // Safety fallback (should not be needed).\n    if ((int)ans.size() > 4 * N * N) {\n        ans.clear();\n        for (int p = 0; p < P; p++) {\n            auto [i, j] = oni[p];\n            int bestF = -1, bestD = INF;\n            for (int f : opts[p]) {\n                if (depth[p][f] < bestD) {\n                    bestD = depth[p][f];\n                    bestF = f;\n                }\n            }\n            int k = bestD;\n            if (bestF < N) {\n                for (int t = 0; t < k; t++) ans.push_back({'L', i});\n                for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            } else if (bestF < 2 * N) {\n                for (int t = 0; t < k; t++) ans.push_back({'R', i});\n                for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            } else if (bestF < 3 * N) {\n                int col = j;\n                for (int t = 0; t < k; t++) ans.push_back({'U', col});\n                for (int t = 0; t < k; t++) ans.push_back({'D', col});\n            } else {\n                int col = j;\n                for (int t = 0; t < k; t++) ans.push_back({'D', col});\n                for (int t = 0; t < k; t++) ans.push_back({'U', col});\n            }\n        }\n    }\n\n    for (auto [c, p] : ans) {\n        cout << c << ' ' << p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\n#include <atcoder/scc>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic inline long long llabs2(long long x) { return x >= 0 ? x : -x; }\n\nstruct State {\n    vector<int> a, b;\n    vector<int> cnt;\n    long long err = (1LL << 60);\n};\n\nstruct Solver {\n    int N, L;\n    vector<int> T;\n    mt19937_64 rng;\n\n    chrono::steady_clock::time_point st;\n\n    Solver(int N_, int L_, vector<int> T_)\n        : N(N_), L(L_), T(std::move(T_)),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    State simulate(const vector<int>& a, const vector<int>& b) {\n        State res;\n        res.a = a;\n        res.b = b;\n        res.cnt.assign(N, 0);\n\n        int x = 0;\n        res.cnt[0] = 1;\n        for (int step = 1; step < L; step++) {\n            x = (res.cnt[x] & 1) ? a[x] : b[x];\n            res.cnt[x]++;\n        }\n\n        long long err = 0;\n        for (int i = 0; i < N; i++) err += llabs2((long long)res.cnt[i] - T[i]);\n        res.err = err;\n        return res;\n    }\n\n    vector<vector<int>> get_sccs(const vector<int>& a, const vector<int>& b) {\n        scc_graph g(N);\n        for (int i = 0; i < N; i++) {\n            g.add_edge(i, a[i]);\n            g.add_edge(i, b[i]);\n        }\n        return g.scc();\n    }\n\n    void repair_components(vector<int>& a, vector<int>& b, vector<long long>& R) {\n        // Try a few times. Usually one pass is enough.\n        for (int iter = 0; iter < 4; iter++) {\n            auto comps = get_sccs(a, b);\n            if ((int)comps.size() <= 1) return;\n\n            vector<int> comp_id(N, -1);\n            for (int i = 0; i < (int)comps.size(); i++) {\n                for (int v : comps[i]) comp_id[v] = i;\n            }\n\n            int K = (int)comps.size();\n            vector<int> rep(K, -1);\n            for (int i = 0; i < K; i++) {\n                int best = comps[i][0];\n                for (int v : comps[i]) {\n                    if (T[v] < T[best]) best = v;\n                }\n                rep[i] = best;\n            }\n\n            // Connect components in a cycle with minimum-damage rewiring.\n            for (int i = 0; i < K; i++) {\n                int target = rep[(i + 1) % K];\n\n                long long bestKey = (1LL << 62);\n                int bestu = -1, bestslot = -1, bestold = -1;\n\n                for (int u : comps[i]) {\n                    long long w = T[u];\n                    for (int slot = 0; slot < 2; slot++) {\n                        int old = (slot == 0 ? a[u] : b[u]);\n                        if (old == target) {\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestKey = LLONG_MIN;\n                            break;\n                        }\n\n                        long long delta =\n                            llabs2(R[old] + w) + llabs2(R[target] - w)\n                            - llabs2(R[old]) - llabs2(R[target]);\n\n                        int other = (slot == 0 ? b[u] : a[u]);\n                        long long key = delta * 1000000LL + T[u];\n                        if (comp_id[other] == i) key -= 1; // slight preference\n\n                        if (key < bestKey) {\n                            bestKey = key;\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                        }\n                    }\n                    if (bestKey == LLONG_MIN) break;\n                }\n\n                if (bestu != -1 && bestold != target) {\n                    long long w = T[bestu];\n                    R[bestold] += w;\n                    R[target] -= w;\n                    if (bestslot == 0) a[bestu] = target;\n                    else b[bestu] = target;\n                }\n            }\n        }\n    }\n\n    State build_candidate(int mode) {\n        vector<long long> R(N);\n        for (int i = 0; i < N; i++) R[i] = 2LL * T[i];\n\n        vector<int> dest(2 * N, -1);\n        vector<int> first_dest(N, -1);\n\n        vector<int> ids(2 * N);\n        iota(ids.begin(), ids.end(), 0);\n\n        // Different modes for diversification.\n        long long same_pen = (mode % 4 == 0 ? 0 : mode % 4 == 1 ? 50 : mode % 4 == 2 ? 200 : 800);\n        long long self_pen = (mode % 5 == 0 ? 0 : mode % 5 == 1 ? 50 : mode % 5 == 2 ? 200 : mode % 5 == 3 ? 800 : 2000);\n\n        shuffle(ids.begin(), ids.end(), rng);\n        stable_sort(ids.begin(), ids.end(), [&](int p, int q) {\n            int wp = T[p / 2], wq = T[q / 2];\n            if (wp != wq) return wp > wq;\n            return p < q;\n        });\n\n        for (int pid : ids) {\n            int owner = pid / 2;\n            long long w = T[owner];\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(N);\n\n            for (int j = 0; j < N; j++) {\n                long long after = R[j] - w;\n                long long sc = llabs2(after) * 10;\n                if (after < 0) sc += (-after);          // slight overshoot penalty\n                if (first_dest[owner] == j) sc += same_pen;\n                if (j == owner) sc += self_pen;\n                sc += (long long)(rng() % 17);\n                cand.push_back({sc, j});\n            }\n\n            nth_element(cand.begin(), cand.begin() + min(4, N - 1), cand.end());\n            sort(cand.begin(), cand.begin() + min(5, N));\n\n            int pick_lim = min(5, N);\n            int choose = (int)(rng() % pick_lim);\n            int j = cand[choose].second;\n\n            dest[pid] = j;\n            if (first_dest[owner] == -1) first_dest[owner] = j;\n            R[j] -= w;\n        }\n\n        // Local improvement: single moves.\n        for (int pass = 0; pass < 5; pass++) {\n            bool changed = false;\n            shuffle(ids.begin(), ids.end(), rng);\n            for (int pid : ids) {\n                int owner = pid / 2;\n                long long w = T[owner];\n                int u = dest[pid];\n\n                long long bestDelta = 0;\n                int bestV = u;\n                for (int v = 0; v < N; v++) if (v != u) {\n                    long long delta =\n                        llabs2(R[u] + w) + llabs2(R[v] - w)\n                        - llabs2(R[u]) - llabs2(R[v]);\n\n                    if (delta < bestDelta || (delta == bestDelta && (rng() & 1))) {\n                        bestDelta = delta;\n                        bestV = v;\n                    }\n                }\n\n                if (bestV != u && bestDelta < 0) {\n                    R[u] += w;\n                    R[bestV] -= w;\n                    dest[pid] = bestV;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n\n        // Local improvement: random swaps.\n        for (int it = 0; it < 400; it++) {\n            int p = rng() % (2 * N);\n            int q = rng() % (2 * N);\n            if (p == q) continue;\n            int u = dest[p], v = dest[q];\n            if (u == v) continue;\n            long long w1 = T[p / 2], w2 = T[q / 2];\n\n            long long delta =\n                llabs2(R[u] + w1 - w2) + llabs2(R[v] + w2 - w1)\n                - llabs2(R[u]) - llabs2(R[v]);\n\n            if (delta < 0) {\n                R[u] += w1 - w2;\n                R[v] += w2 - w1;\n                swap(dest[p], dest[q]);\n            }\n        }\n\n        vector<int> a(N), b(N);\n        for (int i = 0; i < N; i++) {\n            a[i] = dest[2 * i];\n            b[i] = dest[2 * i + 1];\n            if (rng() & 1) swap(a[i], b[i]);\n        }\n\n        repair_components(a, b, R);\n\n        return simulate(a, b);\n    }\n\n    State hill_climb(State cur) {\n        while (elapsed() < 1.95) {\n            vector<int> over, under;\n            for (int i = 0; i < N; i++) {\n                long long d = (long long)cur.cnt[i] - T[i];\n                if (d > 0) over.push_back(i);\n                if (d < 0) under.push_back(i);\n            }\n\n            sort(over.begin(), over.end(), [&](int x, int y) {\n                return (cur.cnt[x] - T[x]) > (cur.cnt[y] - T[y]);\n            });\n            sort(under.begin(), under.end(), [&](int x, int y) {\n                return (T[x] - cur.cnt[x]) > (T[y] - cur.cnt[y]);\n            });\n\n            bool improved = false;\n            int tries = 0;\n            while (tries < 20 && elapsed() < 1.95) {\n                tries++;\n\n                State nxt = cur;\n                int typ = rng() % 3;\n\n                if (typ == 2) {\n                    // swap a/b on one node\n                    int i;\n                    if (!over.empty() && (rng() & 1)) i = over[rng() % min<int>(10, over.size())];\n                    else i = rng() % N;\n                    if (nxt.a[i] == nxt.b[i]) continue;\n                    swap(nxt.a[i], nxt.b[i]);\n                } else {\n                    int i;\n                    if (!over.empty()) i = over[rng() % min<int>(10, over.size())];\n                    else i = rng() % N;\n\n                    int j;\n                    if (!under.empty()) j = under[rng() % min<int>(10, under.size())];\n                    else j = rng() % N;\n\n                    if (typ == 0) {\n                        if (nxt.a[i] == j) continue;\n                        nxt.a[i] = j;\n                    } else {\n                        if (nxt.b[i] == j) continue;\n                        nxt.b[i] = j;\n                    }\n                }\n\n                nxt = simulate(nxt.a, nxt.b);\n                if (nxt.err < cur.err) {\n                    cur = std::move(nxt);\n                    improved = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    State solve() {\n        State best;\n\n        int mode = 0;\n        while (elapsed() < 1.15) {\n            State cand = build_candidate(mode++);\n            if (cand.err < best.err) best = std::move(cand);\n        }\n\n        best = hill_climb(best);\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    vector<int> T(N);\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    Solver solver(N, L, T);\n    State ans = solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << ans.a[i] << ' ' << ans.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\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\nstruct Solver {\n    static constexpr double INF = 1e100;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<double> cx, cy;\n    vector<vector<double>> distm;\n    vector<uint32_t> morton_code;\n    int used_queries = 0;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffff;\n        x = (x ^ (x << 8)) & 0x00FF00FF;\n        x = (x ^ (x << 4)) & 0x0F0F0F0F;\n        x = (x ^ (x << 2)) & 0x33333333;\n        x = (x ^ (x << 1)) & 0x55555555;\n        return x;\n    }\n\n    static pair<int,int> norm_edge(int a, int b) {\n        if (a > b) swap(a, b);\n        return {a, b};\n    }\n\n    static uint64_t edge_key(int a, int b) {\n        if (a > b) swap(a, b);\n        return (uint64_t(uint32_t(a)) << 32) | uint32_t(b);\n    }\n\n    void input() {\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        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx.resize(N); cy.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n        }\n\n        distm.assign(N, vector<double>(N, 0.0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                double dx = cx[i] - cx[j];\n                double dy = cy[i] - cy[j];\n                double d = sqrt(dx * dx + dy * dy);\n                distm[i][j] = distm[j][i] = d;\n            }\n        }\n\n        morton_code.resize(N);\n        for (int i = 0; i < N; i++) {\n            int xi = int(round(cx[i]));\n            int yi = int(round(cy[i]));\n            xi = max(0, min(16383, xi));\n            yi = max(0, min(16383, yi));\n            morton_code[i] = part1by1((uint32_t)xi) | (part1by1((uint32_t)yi) << 1);\n        }\n    }\n\n    // ---------- basic geometry / order ----------\n\n    vector<int> all_cities() {\n        vector<int> v(N);\n        iota(v.begin(), v.end(), 0);\n        return v;\n    }\n\n    vector<int> order_by_morton() {\n        vector<int> ord = all_cities();\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_by_projection(double dx, double dy) {\n        vector<int> ord = all_cities();\n        double norm = sqrt(dx * dx + dy * dy);\n        dx /= norm; dy /= norm;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double ka = cx[a] * dx + cy[a] * dy;\n            double kb = cx[b] * dx + cy[b] * dy;\n            if (fabs(ka - kb) > 1e-9) return ka < kb;\n            double ta = -cx[a] * dy + cy[a] * dx;\n            double tb = -cx[b] * dy + cy[b] * dx;\n            if (fabs(ta - tb) > 1e-9) return ta < tb;\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_group_by_key(const vector<int>& group, int mode) {\n        vector<int> ord = group;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto key = [&](int v) -> pair<double,double> {\n                if (mode == 0) return {cx[v], cy[v]};\n                if (mode == 1) return {cy[v], cx[v]};\n                if (mode == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n                if (mode == 3) return {cx[v] - cy[v], cx[v] + cy[v]};\n                return {double(morton_code[v]), double(v)};\n            };\n            auto ka = key(a), kb = key(b);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n        return ord;\n    }\n\n    // ---------- MST approximate ----------\n\n    double mst_cost_of_list(const vector<int>& cities) {\n        int n = (int)cities.size();\n        if (n <= 1) return 0.0;\n        vector<double> md(n, INF);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n        double ret = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            ret += md[v];\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) md[i] = d;\n            }\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_small(const vector<int>& cities) {\n        int n = (int)cities.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<double> md(n, INF);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back(norm_edge(cities[v], cities[par[v]]));\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) {\n                    md[i] = d;\n                    par[i] = v;\n                }\n            }\n        }\n        return edges;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_full(const vector<int>& cities) {\n        return approx_mst_edges_small(cities);\n    }\n\n    vector<int> mst_preorder_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        auto edges = approx_mst_edges_full(group);\n        unordered_map<int, vector<int>> adj;\n        adj.reserve(n * 2);\n        for (auto [a, b] : edges) {\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        }\n\n        int root = group[0];\n        for (int v : group) {\n            if (cx[v] + cy[v] < cx[root] + cy[root]) root = v;\n        }\n\n        vector<int> ord;\n        ord.reserve(n);\n        unordered_set<int> vis;\n        vis.reserve(n * 2);\n\n        vector<pair<int,int>> st;\n        st.push_back({root, -1});\n        while (!st.empty()) {\n            auto [v, p] = st.back();\n            st.pop_back();\n            if (vis.count(v)) continue;\n            vis.insert(v);\n            ord.push_back(v);\n\n            auto &neis = adj[v];\n            sort(neis.begin(), neis.end(), [&](int a, int b) {\n                double da = distm[v][a], db = distm[v][b];\n                if (fabs(da - db) > 1e-9) return da > db; // stack push reverse-like\n                return a > b;\n            });\n            for (int to : neis) if (to != p && !vis.count(to)) {\n                st.push_back({to, v});\n            }\n        }\n        if ((int)ord.size() != n) return group;\n        return ord;\n    }\n\n    // ---------- order-partition candidate ----------\n\n    struct OrderEvaluator {\n        const vector<int>& ord;\n        const vector<vector<double>>& distm;\n        int N;\n        vector<vector<double>> cache;\n\n        OrderEvaluator(const vector<int>& ord_, const vector<vector<double>>& distm_)\n            : ord(ord_), distm(distm_), N((int)ord_.size()),\n              cache(N + 1, vector<double>(N + 1, -1.0)) {}\n\n        double seg_cost(int l, int len) {\n            if (len <= 1) return 0.0;\n            double &res = cache[l][len];\n            if (res >= -0.5) return res;\n\n            vector<double> md(len, 1e100);\n            vector<char> used(len, 0);\n            md[0] = 0.0;\n            double ret = 0.0;\n\n            for (int it = 0; it < len; it++) {\n                int v = -1;\n                for (int i = 0; i < len; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                ret += md[v];\n                int cv = ord[l + v];\n                for (int i = 0; i < len; i++) if (!used[i]) {\n                    double d = distm[cv][ord[l + i]];\n                    if (d < md[i]) md[i] = d;\n                }\n            }\n            res = ret;\n            return res;\n        }\n\n        double total_cost(const vector<int>& sizes) {\n            int pos = 0;\n            double ret = 0.0;\n            for (int s : sizes) {\n                ret += seg_cost(pos, s);\n                pos += s;\n            }\n            return ret;\n        }\n\n        vector<int> improve(vector<int> sizes, int passes = 4) {\n            int m = (int)sizes.size();\n            for (int pass = 0; pass < passes; pass++) {\n                bool any = false;\n                int pos = 0;\n                for (int i = 0; i + 1 < m; i++) {\n                    int a = sizes[i], b = sizes[i + 1];\n                    double oldc = seg_cost(pos, a) + seg_cost(pos + a, b);\n                    double newc = seg_cost(pos, b) + seg_cost(pos + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[i], sizes[i + 1]);\n                        any = true;\n                    }\n                    pos += sizes[i];\n                }\n                if (!any) break;\n            }\n            return sizes;\n        }\n    };\n\n    struct Candidate {\n        vector<vector<int>> groups_seq; // group sequence with size multiset = G\n        double score = INF;\n    };\n\n    Candidate candidate_from_order(const vector<int>& ord, const vector<int>& size_seq) {\n        OrderEvaluator eval(ord, distm);\n        auto sizes = eval.improve(size_seq, 5);\n        double sc = eval.total_cost(sizes);\n\n        vector<vector<int>> groups;\n        int pos = 0;\n        for (int s : sizes) {\n            vector<int> grp;\n            grp.reserve(s);\n            for (int i = 0; i < s; i++) grp.push_back(ord[pos + i]);\n            pos += s;\n            groups.push_back(move(grp));\n        }\n        return {groups, sc};\n    }\n\n    // ---------- kd-style recursive partition candidate ----------\n\n    vector<vector<int>> kd_partition_rec(vector<int> cities, vector<int> sizes, int mode, int depth) {\n        if ((int)sizes.size() == 1) {\n            return {cities};\n        }\n\n        int total = 0;\n        for (int x : sizes) total += x;\n\n        int pref = 0;\n        int split_k = 1;\n        int best_diff = total;\n        for (int k = 1; k < (int)sizes.size(); k++) {\n            pref += sizes[k - 1];\n            int diff = abs(total - 2 * pref);\n            if (diff < best_diff) {\n                best_diff = diff;\n                split_k = k;\n            }\n        }\n\n        int left_need = 0;\n        for (int i = 0; i < split_k; i++) left_need += sizes[i];\n\n        auto choose_mode_key = [&](int v, int chosen) -> pair<double,double> {\n            if (chosen == 0) return {cx[v], cy[v]};\n            if (chosen == 1) return {cy[v], cx[v]};\n            if (chosen == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n            return {cx[v] - cy[v], cx[v] + cy[v]};\n        };\n\n        int chosen = 0;\n        if (mode == 0) {\n            double minx = 1e18, maxx = -1e18, miny = 1e18, maxy = -1e18;\n            for (int v : cities) {\n                minx = min(minx, cx[v]);\n                maxx = max(maxx, cx[v]);\n                miny = min(miny, cy[v]);\n                maxy = max(maxy, cy[v]);\n            }\n            chosen = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        } else if (mode == 1) {\n            chosen = depth % 2;\n        } else {\n            double mina = 1e18, maxa = -1e18, minb = 1e18, maxb = -1e18;\n            for (int v : cities) {\n                double a = cx[v] + cy[v];\n                double b = cx[v] - cy[v];\n                mina = min(mina, a); maxa = max(maxa, a);\n                minb = min(minb, b); maxb = max(maxb, b);\n            }\n            chosen = ((maxa - mina) >= (maxb - minb)) ? 2 : 3;\n        }\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            auto ka = choose_mode_key(a, chosen);\n            auto kb = choose_mode_key(b, chosen);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n\n        vector<int> left_cities(cities.begin(), cities.begin() + left_need);\n        vector<int> right_cities(cities.begin() + left_need, cities.end());\n        vector<int> left_sizes(sizes.begin(), sizes.begin() + split_k);\n        vector<int> right_sizes(sizes.begin() + split_k, sizes.end());\n\n        auto gl = kd_partition_rec(left_cities, left_sizes, mode, depth + 1);\n        auto gr = kd_partition_rec(right_cities, right_sizes, mode, depth + 1);\n        gl.insert(gl.end(), gr.begin(), gr.end());\n        return gl;\n    }\n\n    Candidate candidate_from_kd(const vector<int>& size_seq, int mode) {\n        vector<int> cities = all_cities();\n        auto groups = kd_partition_rec(cities, size_seq, mode, 0);\n        double sc = 0.0;\n        for (auto &g : groups) sc += mst_cost_of_list(g);\n        return {groups, sc};\n    }\n\n    // ---------- assign candidate sequence to original group indices ----------\n\n    vector<vector<int>> assign_to_original_indices(const vector<vector<int>>& groups_seq) {\n        unordered_map<int, vector<int>> mp;\n        mp.reserve(M * 2);\n        for (int i = 0; i < M; i++) mp[G[i]].push_back(i);\n        for (auto &kv : mp) reverse(kv.second.begin(), kv.second.end());\n\n        vector<vector<int>> ret(M);\n        for (auto &grp : groups_seq) {\n            int s = (int)grp.size();\n            int idx = mp[s].back();\n            mp[s].pop_back();\n            ret[idx] = grp;\n        }\n        return ret;\n    }\n\n    // ---------- local swap optimization ----------\n\n    double sqdist_city_to_point(int v, double x, double y) {\n        double dx = cx[v] - x;\n        double dy = cy[v] - y;\n        return dx * dx + dy * dy;\n    }\n\n    void recompute_group_info(const vector<vector<int>>& groups, int gid,\n                              vector<double>& gcx, vector<double>& gcy, vector<double>& gcost) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[gid]) {\n            sx += cx[v];\n            sy += cy[v];\n        }\n        gcx[gid] = sx / groups[gid].size();\n        gcy[gid] = sy / groups[gid].size();\n        gcost[gid] = mst_cost_of_list(groups[gid]);\n    }\n\n    void local_swap_optimize(vector<vector<int>>& groups) {\n        vector<double> gcx(M), gcy(M), gcost(M);\n        for (int i = 0; i < M; i++) {\n            recompute_group_info(groups, i, gcx, gcy, gcost);\n        }\n\n        const int PASSES = 2;\n        const int K_NEI = 5;\n        const int K_CAND = 4;\n\n        for (int pass = 0; pass < PASSES; pass++) {\n            bool any = false;\n\n            vector<vector<int>> neigh(M);\n            for (int i = 0; i < M; i++) {\n                vector<pair<double,int>> ds;\n                ds.reserve(M - 1);\n                for (int j = 0; j < M; j++) if (i != j) {\n                    double dx = gcx[i] - gcx[j];\n                    double dy = gcy[i] - gcy[j];\n                    ds.push_back({dx * dx + dy * dy, j});\n                }\n                nth_element(ds.begin(), ds.begin() + min(K_NEI, (int)ds.size()), ds.end());\n                sort(ds.begin(), ds.begin() + min(K_NEI, (int)ds.size()));\n                for (int t = 0; t < min(K_NEI, (int)ds.size()); t++) neigh[i].push_back(ds[t].second);\n            }\n\n            set<pair<int,int>> pairs;\n            for (int i = 0; i < M; i++) {\n                for (int j : neigh[i]) {\n                    if (i < j) pairs.insert({i, j});\n                    else pairs.insert({j, i});\n                }\n            }\n\n            for (auto [a, b] : pairs) {\n                auto pick_candidates = [&](int from, int to) {\n                    vector<pair<double,int>> cand;\n                    cand.reserve(groups[from].size());\n                    for (int idx = 0; idx < (int)groups[from].size(); idx++) {\n                        int v = groups[from][idx];\n                        double score = sqdist_city_to_point(v, gcx[to], gcy[to]) - sqdist_city_to_point(v, gcx[from], gcy[from]);\n                        cand.push_back({score, idx});\n                    }\n                    int k = min(K_CAND, (int)cand.size());\n                    nth_element(cand.begin(), cand.begin() + k, cand.end());\n                    sort(cand.begin(), cand.begin() + k);\n                    vector<int> ret;\n                    for (int i = 0; i < k; i++) ret.push_back(cand[i].second);\n                    return ret;\n                };\n\n                auto ca = pick_candidates(a, b);\n                auto cb = pick_candidates(b, a);\n\n                double old_cost = gcost[a] + gcost[b];\n                double best_new = old_cost;\n                int besta = -1, bestb = -1;\n\n                for (int ia : ca) {\n                    for (int ib : cb) {\n                        vector<int> ga = groups[a];\n                        vector<int> gb = groups[b];\n                        swap(ga[ia], gb[ib]);\n                        double nc = mst_cost_of_list(ga) + mst_cost_of_list(gb);\n                        if (nc + 1e-9 < best_new) {\n                            best_new = nc;\n                            besta = ia;\n                            bestb = ib;\n                        }\n                    }\n                }\n\n                if (besta != -1) {\n                    swap(groups[a][besta], groups[b][bestb]);\n                    recompute_group_info(groups, a, gcx, gcy, gcost);\n                    recompute_group_info(groups, b, gcx, gcy, gcost);\n                    any = true;\n                }\n            }\n\n            if (!any) break;\n        }\n    }\n\n    // ---------- grouping main ----------\n\n    vector<vector<int>> build_groups() {\n        vector<Candidate> cands;\n\n        vector<int> ascG = G;\n        sort(ascG.begin(), ascG.end());\n        vector<int> descG = G;\n        sort(descG.rbegin(), descG.rend());\n\n        vector<vector<int>> size_seqs = {G, ascG, descG};\n\n        // order-based candidates\n        vector<vector<int>> orders;\n        orders.push_back(order_by_morton());\n        orders.push_back(order_by_projection(1, 0));\n        orders.push_back(order_by_projection(0, 1));\n        orders.push_back(order_by_projection(1, 1));\n        orders.push_back(order_by_projection(1, -1));\n        orders.push_back(order_by_projection(cos(M_PI / 8.0), sin(M_PI / 8.0)));\n        orders.push_back(order_by_projection(cos(3 * M_PI / 8.0), sin(3 * M_PI / 8.0)));\n\n        for (auto &ord : orders) {\n            for (auto &sz : size_seqs) {\n                cands.push_back(candidate_from_order(ord, sz));\n            }\n        }\n\n        // kd-based candidates\n        for (auto &sz : size_seqs) {\n            for (int mode = 0; mode < 3; mode++) {\n                cands.push_back(candidate_from_kd(sz, mode));\n            }\n        }\n\n        Candidate best;\n        best.score = INF;\n        for (auto &c : cands) {\n            if (c.score < best.score) best = c;\n        }\n\n        auto groups = assign_to_original_indices(best.groups_seq);\n        local_swap_optimize(groups);\n        return groups;\n    }\n\n    // ---------- route construction with overlapping windows ----------\n\n    vector<pair<int,int>> make_primary_windows_indices(int n) {\n        vector<pair<int,int>> res; // {start, len}\n        if (n < 2) return res;\n        int s = 0;\n        while (true) {\n            int len = min(L, n - s);\n            if (len < 2) break;\n            res.push_back({s, len});\n            if (s + len >= n) break;\n            s = s + len - 1; // overlap 1\n        }\n        return res;\n    }\n\n    vector<pair<int,int>> make_extra_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n <= L) return res;\n\n        auto primary = make_primary_windows_indices(n);\n        set<int> used_starts;\n        for (auto [s, len] : primary) used_starts.insert(s);\n\n        int max_start = n - L;\n        int shift = max(1, (L - 1) / 2);\n\n        for (int i = 0; i + 1 < (int)primary.size(); i++) {\n            int s1 = primary[i].first;\n            int s2 = primary[i + 1].first;\n            int cand = min(max_start, s1 + shift);\n            if (cand > s1 && cand < s2 && !used_starts.count(cand)) {\n                used_starts.insert(cand);\n                res.push_back({cand, L});\n            }\n            int cand2 = max(0, min(max_start, s2 - shift));\n            if (cand2 > s1 && cand2 < s2 && !used_starts.count(cand2)) {\n                used_starts.insert(cand2);\n                res.push_back({cand2, L});\n            }\n        }\n        return res;\n    }\n\n    double approx_union_tree_cost_for_order(const vector<int>& ord) {\n        int n = (int)ord.size();\n        if (n <= 1) return 0.0;\n        if (n <= L) return mst_cost_of_list(ord);\n\n        auto primary = make_primary_windows_indices(n);\n\n        unordered_set<uint64_t> eset;\n        eset.reserve(n * 8);\n\n        for (auto [s, len] : primary) {\n            vector<int> w(ord.begin() + s, ord.begin() + s + len);\n            auto e = approx_mst_edges_small(w);\n            for (auto [a, b] : e) eset.insert(edge_key(a, b));\n        }\n\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        unordered_set<int> vset(ord.begin(), ord.end());\n        DSU dsu(N);\n        double cost = 0.0;\n        int cnt = 0;\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) {\n                cost += e.first;\n                cnt++;\n                if (cnt == n - 1) break;\n            }\n        }\n        if (cnt != n - 1) {\n            // fallback shouldn't happen, but just in case\n            return mst_cost_of_list(ord);\n        }\n        return cost;\n    }\n\n    vector<int> choose_best_local_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        vector<vector<int>> cands;\n        cands.push_back(group);\n        cands.push_back(order_group_by_key(group, 4)); // morton\n        cands.push_back(order_group_by_key(group, 0)); // x\n        cands.push_back(order_group_by_key(group, 1)); // y\n        cands.push_back(order_group_by_key(group, 2)); // x+y\n        cands.push_back(order_group_by_key(group, 3)); // x-y\n        cands.push_back(mst_preorder_order(group));\n\n        double best_score = INF;\n        vector<int> best = group;\n        for (auto &ord : cands) {\n            double sc = approx_union_tree_cost_for_order(ord);\n            if (sc < best_score) {\n                best_score = sc;\n                best = ord;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> query(const vector<int>& cities) {\n        cout << \"? \" << cities.size();\n        for (int v : cities) cout << \" \" << v;\n        cout << endl;\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)cities.size() - 1);\n        for (int i = 0; i < (int)cities.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            ret.push_back(norm_edge(a, b));\n        }\n        used_queries++;\n        return ret;\n    }\n\n    struct GroupPlan {\n        vector<int> order;\n        vector<pair<int,int>> primary;\n        vector<pair<int,int>> extra_candidates;\n    };\n\n    struct ExtraQueryCand {\n        double priority;\n        int gid;\n        int start;\n        int len;\n        bool operator<(const ExtraQueryCand& other) const {\n            if (fabs(priority - other.priority) > 1e-9) return priority > other.priority;\n            if (gid != other.gid) return gid < other.gid;\n            return start < other.start;\n        }\n    };\n\n    vector<pair<int,int>> final_tree_from_edge_union(const vector<int>& group,\n                                                     const unordered_set<uint64_t>& eset) {\n        int n = (int)group.size();\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> ans;\n        ans.reserve(max(0, n - 1));\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) {\n                ans.push_back({a, b});\n                if ((int)ans.size() == n - 1) break;\n            }\n        }\n\n        // safety fallback\n        if ((int)ans.size() != n - 1) {\n            auto approx_all = approx_mst_edges_full(group);\n            ans = approx_all;\n        }\n        return ans;\n    }\n\n    void solve() {\n        input();\n\n        auto groups = build_groups();\n\n        vector<GroupPlan> plans(M);\n        int primary_queries = 0;\n\n        for (int i = 0; i < M; i++) {\n            plans[i].order = choose_best_local_order(groups[i]);\n            int n = (int)plans[i].order.size();\n            plans[i].primary = make_primary_windows_indices(n);\n            plans[i].extra_candidates = make_extra_windows_indices(n);\n            primary_queries += (int)plans[i].primary.size();\n        }\n\n        // primary_queries should be <= Q\n        int remain = max(0, Q - primary_queries);\n\n        vector<ExtraQueryCand> extra_all;\n        for (int i = 0; i < M; i++) {\n            for (auto [s, len] : plans[i].extra_candidates) {\n                vector<int> w(plans[i].order.begin() + s, plans[i].order.begin() + s + len);\n                double pr = mst_cost_of_list(w); // simple importance heuristic\n                extra_all.push_back({pr, i, s, len});\n            }\n        }\n        sort(extra_all.begin(), extra_all.end());\n\n        vector<vector<pair<int,int>>> chosen_extras(M);\n        for (int i = 0; i < min(remain, (int)extra_all.size()); i++) {\n            chosen_extras[extra_all[i].gid].push_back({extra_all[i].start, extra_all[i].len});\n        }\n\n        vector<unordered_set<uint64_t>> edge_unions(M);\n        for (int i = 0; i < M; i++) edge_unions[i].reserve(max(8, (int)groups[i].size() * 4));\n\n        // Query all primary windows\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        // Query selected extra windows\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : chosen_extras[gid]) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        // Build final trees\n        vector<vector<pair<int,int>>> answer_edges(M);\n        for (int gid = 0; gid < M; gid++) {\n            answer_edges[gid] = final_tree_from_edge_union(plans[gid].order, edge_unions[gid]);\n        }\n\n        cout << \"!\" << endl;\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (int i = 0; i < (int)ord.size(); i++) {\n                if (i) cout << ' ';\n                cout << ord[i];\n            }\n            cout << '\\n';\n            for (auto [a, b] : answer_edges[gid]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int POS = N * N;          // 400\nstatic constexpr int NONE = POS;           // 400\nstatic constexpr int BNUM = POS + 1;       // 401\nstatic constexpr int STATES = POS * BNUM;  // 160400\n\nstatic constexpr int INF = 30000;\nstatic constexpr int MAXDIST = 2000; // enough (pure Manhattan route <= 1482)\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nint opp[4] = {1, 0, 3, 2};\nchar dch[4] = {'U', 'D', 'L', 'R'};\n\ninline int sid(int pos, int b) { return pos * BNUM + b; }\ninline int pos_of(int s) { return s / BNUM; }\ninline int block_of(int s) { return s % BNUM; }\ninline bool valid_state(int pos, int b) { return b == NONE || b != pos; }\n\nint neigh[POS][4];\nunsigned short slide_to[BNUM][POS][4];\n\n// reverse predecessors for Slide only:\n// revSlide[b][p] = list of q such that from (q,b) one Slide reaches (p,b)\nstatic vector<unsigned short> revSlide[BNUM][POS];\n\n// dist_all[k * STATES + s]\n// k = 0..M-2\nvector<unsigned short> dist_all;\n\n// buckets for bucketed shortest path\nstatic vector<int> buckets[MAXDIST + 1];\n\nvoid precompute() {\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int p = r * N + c;\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                    neigh[p][d] = nr * N + nc;\n                } else {\n                    neigh[p][d] = -1;\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int p = 0; p < POS; p++) {\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; d++) {\n                int cr = r, cc = c;\n                while (true) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) break;\n                    int np = nr * N + nc;\n                    if (b != NONE && np == b) break;\n                    cr = nr;\n                    cc = nc;\n                }\n                slide_to[b][p][d] = (unsigned short)(cr * N + cc);\n            }\n        }\n    }\n\n    // build reverse slide lists\n    for (int b = 0; b < BNUM; b++) {\n        for (int q = 0; q < POS; q++) {\n            if (!valid_state(q, b)) continue;\n            for (int d = 0; d < 4; d++) {\n                int p = slide_to[b][q][d];\n                if (p != q && valid_state(p, b)) {\n                    revSlide[b][p].push_back((unsigned short)q);\n                }\n            }\n        }\n    }\n}\n\ninline unsigned short* stage_ptr(int k) {\n    return dist_all.data() + (size_t)k * STATES;\n}\n\nvoid compute_stage_dist(int k, const vector<int>& pts, int M) {\n    unsigned short* dist = stage_ptr(k);\n    for (int i = 0; i < STATES; i++) dist[i] = INF;\n    for (int i = 0; i <= MAXDIST; i++) buckets[i].clear();\n\n    int target_next = pts[k + 1];\n    unsigned short* next_dist = (k + 1 < M - 1 ? stage_ptr(k + 1) : nullptr);\n\n    int max_used = 0;\n\n    // initialize all valid sink states at position target_next\n    for (int b = 0; b < BNUM; b++) {\n        if (!valid_state(target_next, b)) continue;\n        int s = sid(target_next, b);\n        unsigned short init_cost = (k + 1 == M - 1 ? 0 : next_dist[s]);\n        dist[s] = init_cost;\n        if (init_cost <= MAXDIST) {\n            buckets[init_cost].push_back(s);\n            if ((int)init_cost > max_used) max_used = init_cost;\n        }\n    }\n\n    auto relax = [&](int ns, int nd) {\n        if (nd > MAXDIST) return;\n        if (nd < dist[ns]) {\n            dist[ns] = (unsigned short)nd;\n            buckets[nd].push_back(ns);\n            if (nd > max_used) max_used = nd;\n        }\n    };\n\n    for (int cd = 0; cd <= max_used; cd++) {\n        auto& bk = buckets[cd];\n        for (size_t it = 0; it < bk.size(); it++) {\n            int s = bk[it];\n            if (dist[s] != cd) continue;\n\n            int p = pos_of(s);\n            int b = block_of(s);\n            int nd = cd + 1;\n\n            // Reverse of Move:\n            // any adjacent q can move into p if q is not blocked\n            for (int d = 0; d < 4; d++) {\n                int q = neigh[p][d];\n                if (q == -1) continue;\n                if (!valid_state(q, b)) continue;\n                relax(sid(q, b), nd);\n            }\n\n            // Reverse of Slide:\n            for (unsigned short q : revSlide[b][p]) {\n                relax(sid((int)q, b), nd);\n            }\n\n            // Reverse of Alter (toggle adjacent block)\n            if (b == NONE) {\n                // predecessor can be (p, adj_block)\n                for (int d = 0; d < 4; d++) {\n                    int a = neigh[p][d];\n                    if (a == -1) continue;\n                    // (p, a) is always valid because a is adjacent != p\n                    relax(sid(p, a), nd);\n                }\n            } else {\n                // predecessor can be (p, NONE) iff block b is adjacent to p\n                bool adjacent = false;\n                for (int d = 0; d < 4; d++) {\n                    if (neigh[p][d] == b) {\n                        adjacent = true;\n                        break;\n                    }\n                }\n                if (adjacent) {\n                    relax(sid(p, NONE), nd);\n                }\n            }\n        }\n    }\n}\n\nstruct Action {\n    char a, d;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    int Nin, M;\n    cin >> Nin >> M;\n    vector<int> pts(M);\n    for (int i = 0; i < M; i++) {\n        int r, c;\n        cin >> r >> c;\n        pts[i] = r * N + c;\n    }\n\n    if (M == 1) {\n        return 0;\n    }\n\n    dist_all.assign((size_t)(M - 1) * STATES, (unsigned short)INF);\n\n    // Backward DP over stages\n    for (int k = M - 2; k >= 0; k--) {\n        compute_stage_dist(k, pts, M);\n    }\n\n    vector<Action> ans;\n    ans.reserve(1600);\n\n    int stage = 0;\n    int cur_pos = pts[0];\n    int cur_block = NONE;\n\n    auto dist_of = [&](int stg, int pos, int b) -> int {\n        return stage_ptr(stg)[sid(pos, b)];\n    };\n\n    while (stage < M - 1) {\n        int target = pts[stage + 1];\n        if (cur_pos == target) {\n            stage++;\n            continue;\n        }\n\n        unsigned short* dist = stage_ptr(stage);\n        int s = sid(cur_pos, cur_block);\n        int curd = dist[s];\n\n        bool found = false;\n        Action best_act{};\n        int best_pos = -1, best_block = -1;\n\n        auto try_take = [&](char ac, int dir, int np, int nb) {\n            if (!valid_state(np, nb)) return false;\n            int ns = sid(np, nb);\n            if (dist[ns] + 1 != curd) return false;\n\n            // Prefer directly reaching the next target if possible\n            int pri = (np == target ? 0 : 1);\n            int cur_best_pri = found ? (best_pos == target ? 0 : 1) : 2;\n\n            if (!found || pri < cur_best_pri) {\n                found = true;\n                best_act = {ac, dch[dir]};\n                best_pos = np;\n                best_block = nb;\n                return true;\n            }\n            return false;\n        };\n\n        // Try Slide first, then Move, then Alter\n        // (Tie doesn't affect optimality, just makes paths a bit cleaner.)\n        for (int dir = 0; dir < 4; dir++) {\n            int sp = slide_to[cur_block][cur_pos][dir];\n            if (sp != cur_pos) {\n                try_take('S', dir, sp, cur_block);\n            }\n        }\n        for (int dir = 0; dir < 4; dir++) {\n            int np = neigh[cur_pos][dir];\n            if (np != -1 && np != cur_block) {\n                try_take('M', dir, np, cur_block);\n            }\n        }\n        for (int dir = 0; dir < 4; dir++) {\n            int ap = neigh[cur_pos][dir];\n            if (ap == -1) continue;\n            if (cur_block == NONE) {\n                try_take('A', dir, cur_pos, ap);\n            } else if (cur_block == ap) {\n                try_take('A', dir, cur_pos, NONE);\n            }\n        }\n\n        // Safety fallback: should never happen\n        if (!found) {\n            // simple direct move fallback\n            int r = cur_pos / N, c = cur_pos % N;\n            int tr = target / N, tc = target % N;\n            if (r < tr) {\n                if (cur_block == neigh[cur_pos][1]) {\n                    ans.push_back({'A', 'D'});\n                    cur_block = NONE;\n                } else {\n                    ans.push_back({'M', 'D'});\n                    cur_pos = neigh[cur_pos][1];\n                }\n            } else if (r > tr) {\n                if (cur_block == neigh[cur_pos][0]) {\n                    ans.push_back({'A', 'U'});\n                    cur_block = NONE;\n                } else {\n                    ans.push_back({'M', 'U'});\n                    cur_pos = neigh[cur_pos][0];\n                }\n            } else if (c < tc) {\n                if (cur_block == neigh[cur_pos][3]) {\n                    ans.push_back({'A', 'R'});\n                    cur_block = NONE;\n                } else {\n                    ans.push_back({'M', 'R'});\n                    cur_pos = neigh[cur_pos][3];\n                }\n            } else {\n                if (cur_block == neigh[cur_pos][2]) {\n                    ans.push_back({'A', 'L'});\n                    cur_block = NONE;\n                } else {\n                    ans.push_back({'M', 'L'});\n                    cur_pos = neigh[cur_pos][2];\n                }\n            }\n        } else {\n            ans.push_back(best_act);\n            cur_pos = best_pos;\n            cur_block = best_block;\n        }\n\n        if ((int)ans.size() > 2 * N * M) break;\n    }\n\n    if ((int)ans.size() > 2 * N * M) {\n        ans.resize(2 * N * M);\n    }\n\n    for (auto &x : ans) {\n        cout << x.a << ' ' << x.d << '\\n';\n    }\n    return 0;\n}"},"4":{"ahc001":"#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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct State {\n    double score;\n    vector<Rect> rects;\n};\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr double TL = 4.95;\n\nint n;\nvector<int> X, Y;\nvector<long long> Rr;\n\nTimer timer;\nmt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline long long area(const Rect& r) {\n    return 1LL * (r.c - r.a) * (r.d - r.b);\n}\n\ninline double sat(long long s, long long r) {\n    double q = (double)min(s, r) / (double)max(s, r);\n    double t = 1.0 - q;\n    return 1.0 - t * t;\n}\n\ninline double local_score(const Rect& r, int i) {\n    return sat(area(r), Rr[i]);\n}\n\ndouble total_score(const vector<Rect>& rects) {\n    double res = 0.0;\n    for (int i = 0; i < n; ++i) res += local_score(rects[i], i);\n    return res;\n}\n\ninline bool hoverlap(const Rect& x, const Rect& y) {\n    return max(x.a, y.a) < min(x.c, y.c);\n}\n\ninline bool voverlap(const Rect& x, const Rect& y) {\n    return max(x.b, y.b) < min(x.d, y.d);\n}\n\n// ============================================================\n// Initial construction by recursive guillotine partition\n// ============================================================\n\nstruct Cand {\n    long double cost;\n    bool vertical;\n    int k;\n    int cut;\n};\n\nvoid split_rec(const vector<int>& ids, int L, int R, int B, int T,\n               vector<Rect>& leaf_box, bool randomized, long double shape_lambda) {\n    int m = (int)ids.size();\n    if (m == 1) {\n        leaf_box[ids[0]] = {L, B, R, T};\n        return;\n    }\n\n    long long sumR = 0;\n    for (int id : ids) sumR += Rr[id];\n\n    vector<int> sx = ids, sy = ids;\n    sort(sx.begin(), sx.end(), [&](int i, int j) { return X[i] < X[j]; });\n    sort(sy.begin(), sy.end(), [&](int i, int j) { return Y[i] < Y[j]; });\n\n    vector<Cand> cands;\n    cands.reserve(2 * (m - 1));\n\n    int W = R - L;\n    int H = T - B;\n\n    // Vertical\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sx[k - 1]];\n            int minC = X[sx[k - 1]] + 1;\n            int maxC = X[sx[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)L + (long double)W * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int w1 = cut - L;\n            int w2 = R - cut;\n            if (w1 <= 0 || w2 <= 0) continue;\n\n            long double desiredW = (long double)W * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)w1 - desiredW) / (long double)W;\n\n            long double shape = fabsl(log((long double)w1 / (long double)H))\n                              + fabsl(log((long double)w2 / (long double)H));\n\n            cands.push_back({err + shape_lambda * shape, true, k, cut});\n        }\n    }\n\n    // Horizontal\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sy[k - 1]];\n            int minC = Y[sy[k - 1]] + 1;\n            int maxC = Y[sy[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)B + (long double)H * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int h1 = cut - B;\n            int h2 = T - cut;\n            if (h1 <= 0 || h2 <= 0) continue;\n\n            long double desiredH = (long double)H * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)h1 - desiredH) / (long double)H;\n\n            long double shape = fabsl(log((long double)W / (long double)h1))\n                              + fabsl(log((long double)W / (long double)h2));\n\n            cands.push_back({err + shape_lambda * shape, false, k, cut});\n        }\n    }\n\n    if (cands.empty()) {\n        int k = m / 2;\n        int cut = max(X[sx[k - 1]] + 1, min(X[sx[k]], (L + R) / 2));\n        cut = max(L + 1, min(R - 1, cut));\n        vector<int> left(sx.begin(), sx.begin() + k);\n        vector<int> right(sx.begin() + k, sx.end());\n        split_rec(left, L, cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, cut, R, B, T, leaf_box, randomized, shape_lambda);\n        return;\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Cand& p, const Cand& q) {\n        return p.cost < q.cost;\n    });\n\n    int pick = 0;\n    if (randomized) {\n        int top = min<int>(6, cands.size());\n        vector<long long> w(top);\n        long long s = 0;\n        for (int i = 0; i < top; ++i) {\n            w[i] = top - i;\n            s += w[i];\n        }\n        long long z = (long long)(rng() % s);\n        int chosen = 0;\n        while (z >= w[chosen]) {\n            z -= w[chosen];\n            ++chosen;\n        }\n        pick = chosen;\n    }\n\n    Cand best = cands[pick];\n\n    if (best.vertical) {\n        vector<int> left(sx.begin(), sx.begin() + best.k);\n        vector<int> right(sx.begin() + best.k, sx.end());\n        split_rec(left, L, best.cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, best.cut, R, B, T, leaf_box, randomized, shape_lambda);\n    } else {\n        vector<int> down(sy.begin(), sy.begin() + best.k);\n        vector<int> up(sy.begin() + best.k, sy.end());\n        split_rec(down, L, R, B, best.cut, leaf_box, randomized, shape_lambda);\n        split_rec(up, L, R, best.cut, T, leaf_box, randomized, shape_lambda);\n    }\n}\n\nRect place_inside_box(const Rect& box, int id) {\n    int W = box.c - box.a;\n    int H = box.d - box.b;\n    long long boxA = 1LL * W * H;\n    long long target = Rr[id];\n\n    if (boxA <= target) return box;\n\n    long long bestA = -1;\n    int bestW = 1, bestH = 1;\n    long long bestShape = (1LL << 60);\n\n    for (int w = 1; w <= W; ++w) {\n        long long h = min<long long>(H, target / w);\n        if (h <= 0) continue;\n        long long a = 1LL * w * h;\n        long long shp = llabs((long long)w - h);\n        if (a > bestA || (a == bestA && shp < bestShape)) {\n            bestA = a;\n            bestW = w;\n            bestH = (int)h;\n            bestShape = shp;\n        }\n    }\n\n    int loA = max(box.a, X[id] + 1 - bestW);\n    int hiA = min(X[id], box.c - bestW);\n    int a = clamp(X[id] - bestW / 2, loA, hiA);\n    int c = a + bestW;\n\n    int loB = max(box.b, Y[id] + 1 - bestH);\n    int hiB = min(Y[id], box.d - bestH);\n    int b = clamp(Y[id] - bestH / 2, loB, hiB);\n    int d = b + bestH;\n\n    return {a, b, c, d};\n}\n\nvector<Rect> build_solution(bool randomized) {\n    vector<int> ids(n);\n    iota(ids.begin(), ids.end(), 0);\n\n    long double shape_lambda;\n    if (!randomized) {\n        shape_lambda = 0.0015L;\n    } else {\n        int t = (int)(rng() % 5);\n        if (t == 0) shape_lambda = 0.0L;\n        else if (t == 1) shape_lambda = 0.0006L;\n        else if (t == 2) shape_lambda = 0.0012L;\n        else if (t == 3) shape_lambda = 0.0020L;\n        else shape_lambda = 0.0035L;\n    }\n\n    vector<Rect> boxes(n);\n    split_rec(ids, 0, BOARD, 0, BOARD, boxes, randomized, shape_lambda);\n\n    vector<Rect> rects(n);\n    for (int i = 0; i < n; ++i) rects[i] = place_inside_box(boxes[i], i);\n    return rects;\n}\n\n// ============================================================\n// Cheap side-wise local hill climbing\n// ============================================================\n\nstruct Op {\n    double gain = 0.0;\n    Rect nr;\n};\n\nvector<int> candidate_steps(long long diff, int dim, int tmax) {\n    vector<int> cand;\n    cand.reserve(24);\n    cand.push_back(1);\n    cand.push_back(tmax);\n\n    long double q = (long double)diff / (long double)dim;\n    long long f = (long long)floor((double)q);\n    long long c = (long long)ceil((double)q);\n    for (int d = -3; d <= 3; ++d) {\n        cand.push_back((int)(f + d));\n        cand.push_back((int)(c + d));\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n    vector<int> res;\n    for (int t : cand) if (1 <= t && t <= tmax) res.push_back(t);\n    return res;\n}\n\nOp best_operation_for(int i, const vector<Rect>& rects) {\n    const Rect& curR = rects[i];\n    long long s = area(curR);\n    long long target = Rr[i];\n    double curSat = sat(s, target);\n\n    Op best;\n    best.nr = curR;\n\n    int w = curR.c - curR.a;\n    int h = curR.d - curR.b;\n\n    if (s < target) {\n        // left expand\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].c <= curR.a) {\n                    bound = max(bound, rects[j].c);\n                }\n            }\n            int tmax = curR.a - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right expand\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].a >= curR.c) {\n                    bound = min(bound, rects[j].a);\n                }\n            }\n            int tmax = bound - curR.c;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down expand\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].d <= curR.b) {\n                    bound = max(bound, rects[j].d);\n                }\n            }\n            int tmax = curR.b - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up expand\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].b >= curR.d) {\n                    bound = min(bound, rects[j].b);\n                }\n            }\n            int tmax = bound - curR.d;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    if (s > target) {\n        // left shrink\n        {\n            int tmax = X[i] - curR.a;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // right shrink\n        {\n            int tmax = curR.c - (X[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // down shrink\n        {\n            int tmax = Y[i] - curR.b;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        // up shrink\n        {\n            int tmax = curR.d - (Y[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double nsat = sat(ns, target);\n                    double gain = nsat - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid side_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            double sc = local_score(rects[i], i);\n            double noise = (double)(rng() & 1023) * 1e-12;\n            ord.push_back({sc + noise, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        for (auto [_, i] : ord) {\n            if (timer.elapsed() >= end_time) break;\n            while (timer.elapsed() < end_time) {\n                Op op = best_operation_for(i, rects);\n                if (op.gain <= 1e-15) break;\n                rects[i] = op.nr;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Stronger exact single-rectangle re-optimization\n// ============================================================\n\nRect exact_best_for(int i, const vector<Rect>& rects) {\n    const Rect& cur = rects[i];\n    const long long target = Rr[i];\n    double bestSc = local_score(cur, i);\n    Rect best = cur;\n\n    vector<int> bottoms, tops;\n    bottoms.reserve(n + 8);\n    tops.reserve(n + 8);\n\n    bottoms.push_back(0);\n    bottoms.push_back(Y[i]);\n    bottoms.push_back(cur.b);\n\n    tops.push_back(BOARD);\n    tops.push_back(Y[i] + 1);\n    tops.push_back(cur.d);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        if (rects[j].d <= Y[i]) bottoms.push_back(rects[j].d);\n        if (rects[j].b > Y[i]) tops.push_back(rects[j].b);\n    }\n\n    sort(bottoms.begin(), bottoms.end());\n    bottoms.erase(unique(bottoms.begin(), bottoms.end()), bottoms.end());\n    sort(tops.begin(), tops.end());\n    tops.erase(unique(tops.begin(), tops.end()), tops.end());\n\n    auto try_rect = [&](int b, int d, int left, int right) {\n        if (!(b <= Y[i] && Y[i] < d)) return;\n        int H = d - b;\n        int maxW = right - left;\n        if (H <= 0 || maxW <= 0) return;\n\n        vector<int> ws;\n        ws.reserve(20);\n        ws.push_back(1);\n        ws.push_back(maxW);\n        ws.push_back(cur.c - cur.a);\n\n        long double ideal = (long double)target / (long double)H;\n        long long f = (long long)floor((double)ideal);\n        long long c = (long long)ceil((double)ideal);\n        for (int dt = -3; dt <= 3; ++dt) {\n            ws.push_back((int)(f + dt));\n            ws.push_back((int)(c + dt));\n        }\n\n        sort(ws.begin(), ws.end());\n        ws.erase(unique(ws.begin(), ws.end()), ws.end());\n\n        for (int w : ws) {\n            if (w < 1 || w > maxW) continue;\n\n            int loA = max(left, X[i] + 1 - w);\n            int hiA = min(X[i], right - w);\n            if (loA > hiA) continue;\n\n            int pref = cur.a;\n            if (pref < loA || pref > hiA) pref = X[i] - w / 2;\n            int a = clamp(pref, loA, hiA);\n            int c2 = a + w;\n\n            Rect cand{a, b, c2, d};\n            double sc = local_score(cand, i);\n\n            if (sc > bestSc + 1e-15) {\n                bestSc = sc;\n                best = cand;\n            } else if (fabs(sc - bestSc) <= 1e-15) {\n                long long da = llabs(area(cand) - target);\n                long long db = llabs(area(best) - target);\n                if (da < db) {\n                    best = cand;\n                } else if (da == db) {\n                    int moveCand = abs(cand.a - cur.a) + abs(cand.b - cur.b) + abs(cand.c - cur.c) + abs(cand.d - cur.d);\n                    int moveBest = abs(best.a - cur.a) + abs(best.b - cur.b) + abs(best.c - cur.c) + abs(best.d - cur.d);\n                    if (moveCand < moveBest) best = cand;\n                }\n            }\n        }\n    };\n\n    for (int b : bottoms) {\n        if (b > Y[i]) continue;\n        for (int d : tops) {\n            if (d <= Y[i] || b >= d) continue;\n\n            int left = 0, right = BOARD;\n            bool invalid = false;\n\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.d <= b || d <= o.b) continue; // no vertical overlap\n\n                if (o.a <= X[i] && X[i] < o.c) {\n                    invalid = true;\n                    break;\n                }\n                if (o.c <= X[i]) left = max(left, o.c);\n                else if (o.a > X[i]) right = min(right, o.a);\n            }\n            if (invalid || left >= right) continue;\n\n            try_rect(b, d, left, right);\n        }\n    }\n\n    return best;\n}\n\nvoid exact_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            ord.push_back({local_score(rects[i], i), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        int K = min(n, 24);\n\n        for (int z = 0; z < K; ++z) {\n            if (timer.elapsed() >= end_time) break;\n            int i = ord[z].second;\n\n            Rect nr = exact_best_for(i, rects);\n            if (local_score(nr, i) > local_score(rects[i], i) + 1e-15) {\n                rects[i] = nr;\n                changed = true;\n\n                // After a bigger reshape, a few cheap one-side tweaks often help.\n                while (timer.elapsed() < end_time) {\n                    Op op = best_operation_for(i, rects);\n                    if (op.gain <= 1e-15) break;\n                    rects[i] = op.nr;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid add_state(vector<State>& states, vector<Rect> rects) {\n    double sc = total_score(rects);\n    states.push_back({sc, std::move(rects)});\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)states.size() > 4) states.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    X.resize(n);\n    Y.resize(n);\n    Rr.resize(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> X[i] >> Y[i] >> Rr[i];\n    }\n\n    vector<State> states;\n    add_state(states, build_solution(false));\n\n    // Diversified initial solutions\n    double init_end = 0.75;\n    while (timer.elapsed() < init_end) {\n        add_state(states, build_solution(true));\n    }\n\n    // Cheap polishing for top candidates\n    double polish_end = 2.4;\n    for (int i = 0; i < (int)states.size(); ++i) {\n        double now = timer.elapsed();\n        if (now >= polish_end) break;\n        double slice = (polish_end - now) / (double)(states.size() - i);\n        side_improve(states[i].rects, now + slice);\n        states[i].score = total_score(states[i].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<Rect> best = states[0].rects;\n\n    // Stronger final optimization focused on difficult rectangles\n    exact_improve(best, 4.75);\n\n    // Final cheap cleanup\n    side_improve(best, TL);\n\n    for (int i = 0; i < n; ++i) {\n        cout << best[i].a << ' ' << best[i].b << ' ' << best[i].c << ' ' << best[i].d << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int C = N * N;\n    static constexpr double TL = 1.95;\n\n    int si, sj, start;\n    array<int, C> tile{};\n    array<int, C> val{};\n    array<array<int, 4>, C> adj{};\n    array<uint8_t, C> deg{};\n\n    int M = 0;\n\n    // tile info\n    vector<int> tileSize;\n    vector<int> tileSum;\n    vector<int> tileMax;\n    vector<int> tileExp2;   // heuristic expected contribution * 2\n    vector<int> tileUB;     // optimistic upper bound contribution\n\n    vector<unsigned char> vis;\n\n    vector<int> cellSeen;\n    vector<int> cellComp;\n    vector<int> tileSeen;\n    int evalStamp = 1;\n    int tileStamp = 1;\n    array<int, C> qbuf{};\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n\n    struct Params {\n        int wExp2;\n        int wUb;\n        int wTiles;\n        int wImm;\n        int wBranches;\n        int wDeg;\n        double q;\n        int exactLimit;\n    };\n\n    struct ReachInfo {\n        int selExp2 = 0;\n        int selUb = 0;\n        int selTiles = 0;\n\n        int maxUb = 0;\n        int maxTiles = 0;\n\n        int branches = 0;\n        int availDeg = 0;\n    };\n\n    struct Cand {\n        int to;\n        int eval;\n        int imm;\n        int exp2;\n        int ub;\n        int tiles;\n        int branches;\n        int availDeg;\n    };\n\n    struct Solution {\n        vector<int> seq;\n        vector<int> pref;\n        int score = 0;\n        uint64_t hash = 0;\n    };\n\n    vector<Solution> elite;\n    Solution bestSol;\n\n    // exact search state\n    vector<int> exactBestPath;\n    vector<int> exactCurPath;\n    int exactBestScore = 0;\n    bool exactAbort = false;\n    int exactNodes = 0;\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int r, int c) const { return r * N + c; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> si >> sj;\n        start = id(si, sj);\n\n        int mxTile = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int t;\n                cin >> t;\n                tile[id(r, c)] = t;\n                mxTile = max(mxTile, t);\n            }\n        }\n        M = mxTile + 1;\n\n        tileSize.assign(M, 0);\n        tileSum.assign(M, 0);\n        tileMax.assign(M, 0);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p;\n                cin >> p;\n                int v = id(r, c);\n                val[v] = p;\n                int t = tile[v];\n                tileSize[t]++;\n                tileSum[t] += p;\n                tileMax[t] = max(tileMax[t], p);\n            }\n        }\n\n        tileExp2.assign(M, 0);\n        tileUB.assign(M, 0);\n        for (int t = 0; t < M; t++) {\n            if (tileSize[t] == 1) {\n                tileExp2[t] = tileSum[t] * 2;\n                tileUB[t] = tileSum[t];\n            } else {\n                // heuristic: average contribution for domino in *2 scale\n                tileExp2[t] = tileSum[t];\n                tileUB[t] = tileMax[t];\n            }\n        }\n\n        // adjacency between cells of different tiles only\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                int d = 0;\n                const int dr[4] = {-1, 1, 0, 0};\n                const int dc[4] = {0, 0, -1, 1};\n                for (int k = 0; k < 4; k++) {\n                    int nr = r + dr[k], nc = c + dc[k];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    int u = id(nr, nc);\n                    if (tile[u] == tile[v]) continue;\n                    adj[v][d++] = u;\n                }\n                deg[v] = (uint8_t)d;\n            }\n        }\n\n        vis.assign(M, 0);\n        cellSeen.assign(C, 0);\n        cellComp.assign(C, -1);\n        tileSeen.assign(M, 0);\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : seq) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    bool cand_cmp(const Cand& a, const Cand& b) const {\n        if (a.eval != b.eval) return a.eval > b.eval;\n        if (a.tiles != b.tiles) return a.tiles > b.tiles;\n        if (a.exp2 != b.exp2) return a.exp2 > b.exp2;\n        if (a.imm != b.imm) return a.imm > b.imm;\n        if (a.branches != b.branches) return a.branches > b.branches;\n        return a.availDeg > b.availDeg;\n    }\n\n    Params sample_params() {\n        Params p;\n        p.wExp2 = rng.next_int(5, 8);\n        p.wUb = rng.next_int(1, 3);\n        p.wTiles = rng.next_int(50, 120);\n        p.wImm = rng.next_int(14, 24);\n        p.wBranches = rng.next_int(20, 90);\n        p.wDeg = rng.next_int(8, 28);\n        p.q = 0.05 + 0.25 * rng.next_double();\n\n        double e = elapsed();\n        if (e < 0.7) p.exactLimit = 22;\n        else if (e < 1.3) p.exactLimit = 20;\n        else p.exactLimit = 18;\n        return p;\n    }\n\n    inline int comp_metric(int exp2, int ub, int tiles, const Params& par) const {\n        return par.wExp2 * exp2 + par.wUb * ub + par.wTiles * tiles;\n    }\n\n    ReachInfo analyze_from_cell(int cell, const vector<unsigned char>& used, int forbidTile, const Params& par) {\n        ++evalStamp;\n\n        int compExp2[4];\n        int compUb[4];\n        int compTiles[4];\n        int compCnt = 0;\n\n        int branchIds[4];\n        int branchCnt = 0;\n\n        ReachInfo res;\n        int bestMetric = -1;\n\n        for (int i = 0; i < deg[cell]; i++) {\n            int s = adj[cell][i];\n            int ts = tile[s];\n            if (used[ts] || ts == forbidTile) continue;\n\n            res.availDeg++;\n\n            if (cellSeen[s] != evalStamp) {\n                int cid = compCnt++;\n                int qh = 0, qt = 0;\n                qbuf[qt++] = s;\n                cellSeen[s] = evalStamp;\n                cellComp[s] = cid;\n\n                ++tileStamp;\n                int exp2 = 0, ub = 0, tilesCnt = 0;\n\n                while (qh < qt) {\n                    int v = qbuf[qh++];\n                    int tv = tile[v];\n                    if (tileSeen[tv] != tileStamp) {\n                        tileSeen[tv] = tileStamp;\n                        exp2 += tileExp2[tv];\n                        ub += tileUB[tv];\n                        tilesCnt++;\n                    }\n                    for (int j = 0; j < deg[v]; j++) {\n                        int u = adj[v][j];\n                        int tu = tile[u];\n                        if (used[tu] || tu == forbidTile) continue;\n                        if (cellSeen[u] == evalStamp) continue;\n                        cellSeen[u] = evalStamp;\n                        cellComp[u] = cid;\n                        qbuf[qt++] = u;\n                    }\n                }\n\n                compExp2[cid] = exp2;\n                compUb[cid] = ub;\n                compTiles[cid] = tilesCnt;\n            }\n\n            int cid = cellComp[s];\n            int metric = comp_metric(compExp2[cid], compUb[cid], compTiles[cid], par);\n            if (metric > bestMetric ||\n                (metric == bestMetric && compTiles[cid] > res.selTiles) ||\n                (metric == bestMetric && compTiles[cid] == res.selTiles && compUb[cid] > res.selUb)) {\n                bestMetric = metric;\n                res.selExp2 = compExp2[cid];\n                res.selUb = compUb[cid];\n                res.selTiles = compTiles[cid];\n            }\n\n            res.maxUb = max(res.maxUb, compUb[cid]);\n            res.maxTiles = max(res.maxTiles, compTiles[cid]);\n\n            bool exists = false;\n            for (int b = 0; b < branchCnt; b++) {\n                if (branchIds[b] == cid) {\n                    exists = true;\n                    break;\n                }\n            }\n            if (!exists) branchIds[branchCnt++] = cid;\n        }\n\n        res.branches = branchCnt;\n        return res;\n    }\n\n    inline int candidate_eval(int imm, const ReachInfo& ri, const Params& par) const {\n        return par.wImm * imm\n             + par.wExp2 * ri.selExp2\n             + par.wUb * ri.selUb\n             + par.wTiles * ri.selTiles\n             + par.wBranches * ri.branches\n             + par.wDeg * ri.availDeg;\n    }\n\n    vector<int> greedy_suffix_small(int cur, vector<unsigned char> used, const Params& par, int& outScore) {\n        vector<int> path;\n        outScore = 0;\n\n        while (true) {\n            Cand cs[4];\n            int cc = 0;\n            for (int i = 0; i < deg[cur]; i++) {\n                int nx = adj[cur][i];\n                int tnx = tile[nx];\n                if (used[tnx]) continue;\n                ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n                int ev = candidate_eval(val[nx], ri, par);\n                cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n            }\n            if (cc == 0) break;\n            sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n            int nx = cs[0].to;\n            used[tile[nx]] = 1;\n            path.push_back(nx);\n            outScore += val[nx];\n            cur = nx;\n        }\n        return path;\n    }\n\n    void exact_dfs(int cur, vector<unsigned char>& used, int curScore, const Params& par) {\n        if ((++exactNodes & 1023) == 0) {\n            if (elapsed() > TL) {\n                exactAbort = true;\n                return;\n            }\n        }\n\n        ReachInfo ub = analyze_from_cell(cur, used, -1, par);\n        if (curScore + ub.maxUb <= exactBestScore) return;\n\n        Cand cs[4];\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            int tnx = tile[nx];\n            if (used[tnx]) continue;\n            ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n            int ev = candidate_eval(val[nx], ri, par);\n            cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n        }\n\n        if (cc == 0) {\n            if (curScore > exactBestScore) {\n                exactBestScore = curScore;\n                exactBestPath = exactCurPath;\n            }\n            return;\n        }\n\n        sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n\n        for (int i = 0; i < cc; i++) {\n            int nx = cs[i].to;\n            int tnx = tile[nx];\n            used[tnx] = 1;\n            exactCurPath.push_back(nx);\n            exact_dfs(nx, used, curScore + val[nx], par);\n            exactCurPath.pop_back();\n            used[tnx] = 0;\n            if (exactAbort) return;\n        }\n    }\n\n    vector<int> exact_finish(int cur, vector<unsigned char>& used, const Params& par) {\n        exactAbort = false;\n        exactNodes = 0;\n        exactBestPath.clear();\n        exactCurPath.clear();\n        exactBestScore = 0;\n\n        // strong initial lower bound\n        int greedyScore = 0;\n        exactBestPath = greedy_suffix_small(cur, used, par, greedyScore);\n        exactBestScore = greedyScore;\n\n        exact_dfs(cur, used, 0, par);\n        return exactBestPath;\n    }\n\n    void build_prefix_state(const Solution& base, int cutIdx, vector<int>& seq, int& score) {\n        fill(vis.begin(), vis.end(), 0);\n        seq.clear();\n        seq.reserve(C);\n        score = 0;\n\n        for (int i = 0; i <= cutIdx; i++) {\n            int v = base.seq[i];\n            seq.push_back(v);\n            vis[tile[v]] = 1;\n        }\n        score = base.pref[cutIdx];\n    }\n\n    pair<vector<int>, int> grow_from(const Solution& base, int cutIdx, const Params& par) {\n        vector<int> seq;\n        int score = 0;\n        build_prefix_state(base, cutIdx, seq, score);\n\n        int cur = seq.back();\n\n        while (true) {\n            ReachInfo curInfo = analyze_from_cell(cur, vis, -1, par);\n            if (curInfo.maxTiles <= par.exactLimit) {\n                vector<int> suf = exact_finish(cur, vis, par);\n                for (int nx : suf) {\n                    vis[tile[nx]] = 1;\n                    seq.push_back(nx);\n                    score += val[nx];\n                    cur = nx;\n                }\n                break;\n            }\n\n            Cand cs[4];\n            int cc = 0;\n            for (int i = 0; i < deg[cur]; i++) {\n                int nx = adj[cur][i];\n                int tnx = tile[nx];\n                if (vis[tnx]) continue;\n\n                ReachInfo ri = analyze_from_cell(nx, vis, tnx, par);\n                int ev = candidate_eval(val[nx], ri, par);\n                cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n            }\n\n            if (cc == 0) break;\n            sort(cs, cs + cc, [&](const Cand& a, const Cand& b) { return cand_cmp(a, b); });\n\n            int pick = 0;\n            if (cc >= 2) {\n                int gap = cs[0].eval - cs[1].eval;\n                double q = par.q;\n                if (gap > 3000) q *= 0.08;\n                else if (gap > 1500) q *= 0.20;\n                else if (gap > 700) q *= 0.40;\n                else if (gap > 300) q *= 0.70;\n                else q *= 1.10;\n                if (q > 0.80) q = 0.80;\n\n                while (pick + 1 < cc && rng.next_double() < q) pick++;\n            }\n\n            int nx = cs[pick].to;\n            vis[tile[nx]] = 1;\n            seq.push_back(nx);\n            score += val[nx];\n            cur = nx;\n        }\n\n        return {seq, score};\n    }\n\n    Solution make_solution(const vector<int>& seq, int score) {\n        Solution s;\n        s.seq = seq;\n        s.score = score;\n        s.pref.resize(seq.size());\n        int sum = 0;\n        for (int i = 0; i < (int)seq.size(); i++) {\n            sum += val[seq[i]];\n            s.pref[i] = sum;\n        }\n        s.hash = hash_seq(seq);\n        return s;\n    }\n\n    void add_solution(const vector<int>& seq, int score) {\n        Solution sol = make_solution(seq, score);\n\n        if (bestSol.seq.empty() || score > bestSol.score) {\n            bestSol = sol;\n        }\n\n        for (auto& e : elite) {\n            if (e.hash == sol.hash) {\n                if (sol.score > e.score) e = sol;\n                return;\n            }\n        }\n\n        elite.push_back(sol);\n        sort(elite.begin(), elite.end(), [](const Solution& a, const Solution& b) {\n            return a.score > b.score;\n        });\n        if ((int)elite.size() > 6) elite.resize(6);\n    }\n\n    const Solution& choose_parent() {\n        if (elite.empty()) return bestSol;\n        double r = rng.next_double();\n        if (elite.size() == 1) return elite[0];\n        if (r < 0.45) return elite[0];\n        if (r < 0.70) return elite[min<int>(1, elite.size() - 1)];\n        if (r < 0.88) return elite[rng.next_int(0, min<int>(2, elite.size() - 1))];\n        return elite[rng.next_int(0, (int)elite.size() - 1)];\n    }\n\n    int choose_cut(const Solution& base) {\n        int L = (int)base.seq.size() - 1; // moves\n        if (L <= 0) return 0;\n        int maxCut = L - 1; // force actual regrowth when possible\n        if (maxCut <= 0) return 0;\n\n        uint32_t mode = rng.next_u32() % 6;\n        int cut = 0;\n        if (mode == 0) {\n            cut = 0;\n        } else if (mode == 1) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u * u); // early mutation\n        } else if (mode == 2) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u); // uniform\n        } else if (mode == 3) {\n            double u = rng.next_double();\n            cut = maxCut - (int)(maxCut * u * u); // suffix tuning\n        } else {\n            // around middle / late\n            int lo = max(0, maxCut / 3);\n            int hi = maxCut;\n            cut = rng.next_int(lo, hi);\n        }\n        if (cut < 0) cut = 0;\n        if (cut > maxCut) cut = maxCut;\n        return cut;\n    }\n\n    string seq_to_answer(const vector<int>& seq) {\n        string ans;\n        ans.reserve(max(0, (int)seq.size() - 1));\n        for (int i = 1; i < (int)seq.size(); i++) {\n            int a = seq[i - 1], b = seq[i];\n            if (b == a - N) ans.push_back('U');\n            else if (b == a + N) ans.push_back('D');\n            else if (b == a - 1) ans.push_back('L');\n            else ans.push_back('R');\n        }\n        return ans;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        // initial trivial solution\n        bestSol = make_solution(vector<int>{start}, val[start]);\n        elite.clear();\n        elite.push_back(bestSol);\n\n        // a few full restarts first\n        for (int rep = 0; rep < 6 && elapsed() < 0.15; rep++) {\n            Params par = sample_params();\n            auto [seq, score] = grow_from(bestSol, 0, par);\n            add_solution(seq, score);\n        }\n\n        while (elapsed() < TL) {\n            Params par = sample_params();\n\n            bool doRestart = elite.empty() || rng.next_double() < 0.12;\n            if (doRestart) {\n                auto [seq, score] = grow_from(bestSol, 0, par); // bestSol[0] is start\n                add_solution(seq, score);\n                continue;\n            }\n\n            const Solution& base = choose_parent();\n            int cut = choose_cut(base);\n            auto [seq, score] = grow_from(base, cut, par);\n            add_solution(seq, score);\n        }\n\n        cout << seq_to_answer(bestSol.seq) << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horizontal; // true: h[i][j], false: v[i][j]\n    int i, j;\n};\n\nstruct Sample {\n    double y = 0.0;\n    double w = 1.0; // regression weight\n    // hp[row][k] = number of horizontal edges in row=row with index < k used\n    array<array<unsigned char, 30>, 30> hp{};\n    // vp[col][k] = number of vertical edges in col=col with index < k used\n    array<array<unsigned char, 30>, 30> vp{};\n};\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr double PRIOR = 5000.0;\n    static constexpr double INF = 1e100;\n\n    vector<Sample> samples;\n\n    // Global structured model\n    int splitH[N], splitV[N]; // in [1,28], though irrelevant if A==B or C==D\n    double A[N], B[N];        // horizontal row: left/right\n    double C[N], Dv[N];       // vertical col: upper/lower\n\n    // Local edge refinement\n    double edgeH[N][N - 1];\n    double edgeV[N - 1][N];\n    int cntH[N][N - 1];\n    int cntV[N - 1][N];\n\n    static double clamp_cost(double x) {\n        if (x < 1000.0) return 1000.0;\n        if (x > 9000.0) return 9000.0;\n        return x;\n    }\n\n    bool need_rebuild(int turn) const {\n        if (turn == 0) return true;\n        if (turn < 80) return turn % 4 == 0;\n        if (turn < 250) return turn % 8 == 0;\n        return turn % 12 == 0;\n    }\n\n    double global_h(int i, int j) const {\n        return (j < splitH[i] ? A[i] : B[i]);\n    }\n    double global_v(int i, int j) const {\n        return (i < splitV[j] ? C[j] : Dv[j]);\n    }\n\n    double route_h(int i, int j) const {\n        double g = global_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return g;\n        double w = (double)c / (c + 5.0);\n        return clamp_cost(g + w * (edgeH[i][j] - g));\n    }\n    double route_v(int i, int j) const {\n        double g = global_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return g;\n        double w = (double)c / (c + 5.0);\n        return clamp_cost(g + w * (edgeV[i][j] - g));\n    }\n\n    double prior_est_h(int i, int j) const {\n        return cntH[i][j] ? edgeH[i][j] : global_h(i, j);\n    }\n    double prior_est_v(int i, int j) const {\n        return cntV[i][j] ? edgeV[i][j] : global_v(i, j);\n    }\n\n    void rebuild_avg_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                A[i] = B[i] = PRIOR;\n                C[i] = Dv[i] = PRIOR;\n            }\n            return;\n        }\n\n        double Rh[N], Cv[N];\n        for (int i = 0; i < N; i++) {\n            Rh[i] = clamp_cost((A[i] + B[i]) * 0.5);\n            Cv[i] = clamp_cost((C[i] + Dv[i]) * 0.5);\n        }\n\n        vector<double> pred(m, 0.0);\n        auto rebuild_pred = [&]() {\n            fill(pred.begin(), pred.end(), 0.0);\n            for (int n = 0; n < m; n++) {\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (int)samples[n].hp[i][29] * Rh[i];\n                for (int j = 0; j < N; j++) s += (int)samples[n].vp[j][29] * Cv[j];\n                pred[n] = s;\n            }\n        };\n        rebuild_pred();\n\n        double lambda = 35.0 / sqrt((double)m + 1.0) + 1.5;\n\n        for (int it = 0; it < 8; it++) {\n            for (int i = 0; i < N; i++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].hp[i][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + Rh[i] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - Rh[i];\n                if (fabs(delta) > 1e-12) {\n                    Rh[i] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].hp[i][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].vp[j][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + Cv[j] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - Cv[j];\n                if (fabs(delta) > 1e-12) {\n                    Cv[j] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].vp[j][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            A[i] = B[i] = Rh[i];\n            C[i] = Dv[i] = Cv[i];\n        }\n    }\n\n    void compute_pred_split(vector<double>& pred) const {\n        int m = (int)samples.size();\n        pred.assign(m, 0.0);\n        for (int n = 0; n < m; n++) {\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)samples[n].hp[i][splitH[i]];\n                int t = (int)samples[n].hp[i][29];\n                s += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)samples[n].vp[j][splitV[j]];\n                int t = (int)samples[n].vp[j][29];\n                s += u * C[j] + (t - u) * Dv[j];\n            }\n            pred[n] = s;\n        }\n    }\n\n    void cd_update_param(double& param, vector<double>& pred, double lambda,\n                         const function<int(const Sample&)>& feat) {\n        int m = (int)samples.size();\n        double num = 0.0, den = 0.0;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f == 0.0) continue;\n            double w = samples[n].w;\n            num += w * f * (samples[n].y - pred[n] + param * f);\n            den += w * f * f;\n        }\n        double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n        double delta = nv - param;\n        if (fabs(delta) <= 1e-12) return;\n        param = nv;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f) pred[n] += delta * f;\n        }\n    }\n\n    void fit_fixed_splits(vector<double>& pred, double lambda, int iters) {\n        int m = (int)samples.size();\n        if (m == 0) return;\n        compute_pred_split(pred);\n\n        for (int it = 0; it < iters; it++) {\n            for (int i = 0; i < N; i++) {\n                int sp = splitH[i];\n                cd_update_param(A[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    return (int)s.hp[i][sp];\n                });\n                cd_update_param(B[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    int l = (int)s.hp[i][sp];\n                    int t = (int)s.hp[i][29];\n                    return t - l;\n                });\n            }\n            for (int j = 0; j < N; j++) {\n                int sp = splitV[j];\n                cd_update_param(C[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    return (int)s.vp[j][sp];\n                });\n                cd_update_param(Dv[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    int u = (int)s.vp[j][sp];\n                    int t = (int)s.vp[j][29];\n                    return t - u;\n                });\n            }\n        }\n    }\n\n    void optimize_row_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int i = 0; i < N; i++) {\n            int oldsp = splitH[i];\n            double oldA = A[i], oldB = B[i];\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int tot = (int)samples[n].hp[i][29];\n                int oldr = tot - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double bestLoss = 1e300;\n            int bestSp = oldsp;\n            double bestA = oldA, bestB = oldB;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].hp[i][sp];\n                    int t = (int)samples[n].hp[i][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double na = PRIOR, nb = PRIOR;\n                if (det > 1e-9) {\n                    na = (R0 * M11 - R1 * M01) / det;\n                    nb = (R1 * M00 - R0 * M01) / det;\n                }\n                na = clamp_cost(na);\n                nb = clamp_cost(nb);\n\n                double loss =\n                    rr\n                    - 2.0 * na * ar - 2.0 * nb * br\n                    + na * na * aa + 2.0 * na * nb * ab + nb * nb * bb\n                    + lambda * ((na - PRIOR) * (na - PRIOR) + (nb - PRIOR) * (nb - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestA = na;\n                    bestB = nb;\n                }\n            }\n\n            splitH[i] = bestSp;\n            A[i] = bestA;\n            B[i] = bestB;\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int oldt = (int)samples[n].hp[i][29];\n                int oldr = oldt - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n\n                int newl = (int)samples[n].hp[i][bestSp];\n                int newr = oldt - newl;\n                double newc = newl * bestA + newr * bestB;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void optimize_col_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int j = 0; j < N; j++) {\n            int oldsp = splitV[j];\n            double oldC = C[j], oldD = Dv[j];\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int tot = (int)samples[n].vp[j][29];\n                int oldd = tot - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double bestLoss = 1e300;\n            int bestSp = oldsp;\n            double bestC = oldC, bestD = oldD;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].vp[j][sp];\n                    int t = (int)samples[n].vp[j][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double nc = PRIOR, nd = PRIOR;\n                if (det > 1e-9) {\n                    nc = (R0 * M11 - R1 * M01) / det;\n                    nd = (R1 * M00 - R0 * M01) / det;\n                }\n                nc = clamp_cost(nc);\n                nd = clamp_cost(nd);\n\n                double loss =\n                    rr\n                    - 2.0 * nc * ar - 2.0 * nd * br\n                    + nc * nc * aa + 2.0 * nc * nd * ab + nd * nd * bb\n                    + lambda * ((nc - PRIOR) * (nc - PRIOR) + (nd - PRIOR) * (nd - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestC = nc;\n                    bestD = nd;\n                }\n            }\n\n            splitV[j] = bestSp;\n            C[j] = bestC;\n            Dv[j] = bestD;\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int oldt = (int)samples[n].vp[j][29];\n                int oldd = oldt - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n\n                int newu = (int)samples[n].vp[j][bestSp];\n                int newd = oldt - newu;\n                double newc = newu * bestC + newd * bestD;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void prune_weak_splits() {\n        // If a split is weakly supported or segment values are too close,\n        // collapse to a single value for stability.\n        for (int i = 0; i < N; i++) {\n            double leftSup = 0.0, rightSup = 0.0;\n            for (const auto& s : samples) {\n                int l = (int)s.hp[i][splitH[i]];\n                int t = (int)s.hp[i][29];\n                int r = t - l;\n                leftSup += s.w * l;\n                rightSup += s.w * r;\n            }\n            if (min(leftSup, rightSup) < 18.0 || fabs(A[i] - B[i]) < 180.0) {\n                double avg = clamp_cost((leftSup * A[i] + rightSup * B[i]) / max(1.0, leftSup + rightSup));\n                A[i] = B[i] = avg;\n            }\n        }\n        for (int j = 0; j < N; j++) {\n            double upSup = 0.0, downSup = 0.0;\n            for (const auto& s : samples) {\n                int u = (int)s.vp[j][splitV[j]];\n                int t = (int)s.vp[j][29];\n                int d = t - u;\n                upSup += s.w * u;\n                downSup += s.w * d;\n            }\n            if (min(upSup, downSup) < 18.0 || fabs(C[j] - Dv[j]) < 180.0) {\n                double avg = clamp_cost((upSup * C[j] + downSup * Dv[j]) / max(1.0, upSup + downSup));\n                C[j] = Dv[j] = avg;\n            }\n        }\n    }\n\n    void rebuild_split_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                A[i] = B[i] = PRIOR;\n                C[i] = Dv[i] = PRIOR;\n            }\n            return;\n        }\n\n        double lambda = 14.0 / sqrt((double)m + 1.0) + 0.9;\n        vector<double> pred;\n\n        fit_fixed_splits(pred, lambda, 4);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n        fit_fixed_splits(pred, lambda, 3);\n        prune_weak_splits();\n    }\n\n    void rebuild_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n            }\n            return;\n        }\n\n        if (m < 70) rebuild_avg_model();\n        else rebuild_split_model();\n    }\n\n    string shortest_path(int si, int sj, int ti, int tj) const {\n        const int V = N * N;\n        auto id = [&](int x, int y) { return x * N + y; };\n\n        vector<double> dist(V, INF);\n        vector<int> par(V, -1);\n        vector<char> mv(V, 0);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        int s = id(si, sj), t = id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == t) break;\n\n            int x = u / N;\n            int y = u % N;\n\n            auto relax = [&](int nx, int ny, double w, char c) {\n                int v = id(nx, ny);\n                double nd = d + w;\n                if (nd + 1e-12 < dist[v]) {\n                    dist[v] = nd;\n                    par[v] = u;\n                    mv[v] = c;\n                    pq.push({nd, v});\n                }\n            };\n\n            if (x > 0) relax(x - 1, y, route_v(x - 1, y), 'U');\n            if (x + 1 < N) relax(x + 1, y, route_v(x, y), 'D');\n            if (y > 0) relax(x, y - 1, route_h(x, y - 1), 'L');\n            if (y + 1 < N) relax(x, y + 1, route_h(x, y), 'R');\n        }\n\n        string path;\n        for (int cur = t; cur != s; cur = par[cur]) path.push_back(mv[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    void build_sample_and_edges(int si, int sj, const string& path, Sample& smp,\n                                vector<EdgeRef>& edges) const {\n        bool hused[N][N - 1] = {};\n        bool vused[N - 1][N] = {};\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                vused[x - 1][y] = true;\n                edges.push_back({false, x - 1, y});\n                --x;\n            } else if (c == 'D') {\n                vused[x][y] = true;\n                edges.push_back({false, x, y});\n                ++x;\n            } else if (c == 'L') {\n                hused[x][y - 1] = true;\n                edges.push_back({true, x, y - 1});\n                --y;\n            } else if (c == 'R') {\n                hused[x][y] = true;\n                edges.push_back({true, x, y});\n                ++y;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            smp.hp[i][0] = 0;\n            for (int j = 0; j < N - 1; j++) {\n                smp.hp[i][j + 1] = smp.hp[i][j] + (hused[i][j] ? 1 : 0);\n            }\n        }\n        for (int j = 0; j < N; j++) {\n            smp.vp[j][0] = 0;\n            for (int i = 0; i < N - 1; i++) {\n                smp.vp[j][i + 1] = smp.vp[j][i] + (vused[i][j] ? 1 : 0);\n            }\n        }\n    }\n\n    void update_local_edges(const vector<EdgeRef>& edges, double observed, int turn, double sampleWeight) {\n        if (edges.empty()) return;\n\n        vector<double> gains(edges.size());\n        double pred = 0.0, gsum = 0.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            if (e.horizontal) {\n                pred += prior_est_h(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntH[e.i][e.j] + 1.0);\n            } else {\n                pred += prior_est_v(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntV[e.i][e.j] + 1.0);\n            }\n            gsum += gains[k];\n        }\n\n        double residual = observed - pred;\n        double eta;\n        if (turn < 80) eta = 0.40;\n        else if (turn < 250) eta = 0.30;\n        else eta = 0.22;\n\n        double scale = sqrt(sampleWeight);\n        scale = max(0.75, min(1.25, scale));\n        eta *= scale;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            double delta = eta * residual * gains[k] / gsum;\n            delta = max(-1000.0, min(1000.0, delta));\n\n            if (e.horizontal) {\n                if (cntH[e.i][e.j] == 0) edgeH[e.i][e.j] = global_h(e.i, e.j);\n                edgeH[e.i][e.j] = clamp_cost(edgeH[e.i][e.j] + delta);\n                cntH[e.i][e.j]++;\n            } else {\n                if (cntV[e.i][e.j] == 0) edgeV[e.i][e.j] = global_v(e.i, e.j);\n                edgeV[e.i][e.j] = clamp_cost(edgeV[e.i][e.j] + delta);\n                cntV[e.i][e.j]++;\n            }\n        }\n    }\n\npublic:\n    Solver() {\n        for (int i = 0; i < N; i++) {\n            splitH[i] = splitV[i] = 15;\n            A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                edgeH[i][j] = PRIOR;\n                cntH[i][j] = 0;\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                edgeV[i][j] = PRIOR;\n                cntV[i][j] = 0;\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int turn = 0; turn < 1000; turn++) {\n            if (need_rebuild(turn)) rebuild_model();\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            string path = shortest_path(si, sj, ti, tj);\n\n            cout << path << '\\n';\n            cout.flush();\n\n            long long feedback;\n            cin >> feedback;\n\n            Sample smp;\n            smp.y = (double)feedback;\n\n            // Downweight very long samples: multiplicative noise implies larger absolute noise.\n            {\n                double base = max(50000.0, smp.y);\n                double scale = 200000.0 / base;\n                smp.w = scale * scale;\n                smp.w = max(0.35, min(3.0, smp.w));\n            }\n\n            vector<EdgeRef> edges;\n            build_sample_and_edges(si, sj, path, smp, edges);\n\n            samples.push_back(smp);\n            update_local_edges(edges, smp.y, turn, smp.w);\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAXL = 12;\nstatic constexpr int MINL = 2;\nstatic constexpr int WORDS = 13; // ceil(800/64)\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\nstatic inline int ch2v(char c) { return c - 'A'; }\nstatic inline char v2ch(int v) { return char('A' + v); }\n\nusing Bits = array<uint64_t, WORDS>;\n\ntemplate<class B>\nstatic inline bool getbit(const B& b, int i) {\n    return (b[i >> 6] >> (i & 63)) & 1ULL;\n}\ntemplate<class B>\nstatic inline void setbit(B& b, int i) {\n    b[i >> 6] |= 1ULL << (i & 63);\n}\n\nstruct Pattern {\n    int len;\n    uint64_t code;\n    int weight;\n    string s;\n};\n\nstruct ACNode {\n    array<int, 8> next{};\n    int link = 0;\n    vector<int> out;\n    ACNode() { next.fill(-1); }\n};\n\nstruct BeamState {\n    int node = 0;\n    int score = 0;\n    Bits seen{};\n    array<uint8_t, N> s{};\n};\n\nstruct Candidate {\n    array<uint8_t, N> row{};\n    Bits bits{};\n    string canon;\n};\n\nstruct MatrixState {\n    array<array<uint8_t, N>, N> a{};\n    array<Bits, N> row_bits{};\n    array<Bits, N> col_bits{};\n    vector<int> cnt; // how many lines (20 rows + 20 cols) cover each pattern\n    int score = 0;   // total covered original patterns count (weighted by duplicates)\n};\n\nstruct Solver {\n    int M, K;\n    vector<Pattern> pats;\n    vector<int> orig_weight;\n    array<unordered_map<uint64_t, int>, MAXL + 1> id_of;\n    vector<ACNode> ac;\n\n    mt19937_64 rng;\n    Timer timer;\n\n    Solver() : rng(chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    uint64_t encode_string(const string& s) {\n        uint64_t code = 0;\n        for (char c : s) code = (code << 3) | (uint64_t)ch2v(c);\n        return code;\n    }\n\n    string decode_string(uint64_t code, int len) {\n        string s(len, 'A');\n        for (int i = len - 1; i >= 0; --i) {\n            s[i] = v2ch((int)(code & 7ULL));\n            code >>= 3;\n        }\n        return s;\n    }\n\n    void add_pattern_to_ac(const string& s, int id) {\n        int v = 0;\n        for (char c : s) {\n            int x = ch2v(c);\n            if (ac[v].next[x] == -1) {\n                ac[v].next[x] = (int)ac.size();\n                ac.emplace_back();\n            }\n            v = ac[v].next[x];\n        }\n        ac[v].out.push_back(id);\n    }\n\n    void build_ac() {\n        ac.clear();\n        ac.emplace_back();\n        for (int id = 0; id < K; ++id) add_pattern_to_ac(pats[id].s, id);\n\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = ac[0].next[c];\n            if (u == -1) ac[0].next[c] = 0;\n            else {\n                ac[u].link = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            int lk = ac[v].link;\n            if (!ac[lk].out.empty()) {\n                auto& dst = ac[v].out;\n                auto& src = ac[lk].out;\n                dst.insert(dst.end(), src.begin(), src.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = ac[v].next[c];\n                if (u == -1) ac[v].next[c] = ac[lk].next[c];\n                else {\n                    ac[u].link = ac[lk].next[c];\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    Bits compute_bits_seq(const uint8_t seq[N]) const {\n        Bits bits{};\n        bits.fill(0);\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                code = (code << 3) | (uint64_t)seq[(st + len - 1) % N];\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) setbit(bits, it->second);\n                }\n            }\n        }\n        return bits;\n    }\n\n    Bits compute_row_bits(const MatrixState& ms, int r) const {\n        uint8_t seq[N];\n        for (int c = 0; c < N; ++c) seq[c] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    Bits compute_col_bits(const MatrixState& ms, int c) const {\n        uint8_t seq[N];\n        for (int r = 0; r < N; ++r) seq[r] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    int gain_by_bits(const Bits& bits, const vector<int>& weight) const {\n        int g = 0;\n        for (int id = 0; id < K; ++id) if (getbit(bits, id)) g += weight[id];\n        return g;\n    }\n\n    int row_gain_and_bits(const array<uint8_t, N>& row, const vector<int>& weight, Bits& bits) const {\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        bits = compute_bits_seq(seq);\n        return gain_by_bits(bits, weight);\n    }\n\n    string canonical_row(const array<uint8_t, N>& row) const {\n        string best(N, 'Z');\n        for (int sh = 0; sh < N; ++sh) {\n            string cur(N, 'A');\n            for (int i = 0; i < N; ++i) cur[i] = v2ch(row[(i + sh) % N]);\n            if (cur < best) best = cur;\n        }\n        return best;\n    }\n\n    array<uint8_t, N> fallback_row(const vector<int>& weight) {\n        int best_id = -1, best_key = -1;\n        for (int i = 0; i < K; ++i) {\n            int key = weight[i] * pats[i].len;\n            if (key > best_key) best_key = key, best_id = i;\n        }\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n        if (best_id != -1) {\n            const string& s = pats[best_id].s;\n            for (int i = 0; i < (int)s.size() && i < N; ++i) row[i] = ch2v(s[i]);\n        }\n        return row;\n    }\n\n    vector<int> pick_seed_patterns(const vector<int>& weight, int topk, int randk) {\n        vector<pair<int,int>> v;\n        v.reserve(K);\n        for (int i = 0; i < K; ++i) {\n            if (weight[i] <= 0) continue;\n            int key = weight[i] * pats[i].len;\n            v.push_back({key, i});\n        }\n        sort(v.begin(), v.end(), greater<pair<int,int>>());\n\n        vector<int> res;\n        for (int i = 0; i < (int)v.size() && i < topk; ++i) res.push_back(v[i].second);\n\n        vector<int> rest;\n        for (int i = topk; i < (int)v.size(); ++i) rest.push_back(v[i].second);\n        shuffle(rest.begin(), rest.end(), rng);\n        for (int i = 0; i < (int)rest.size() && i < randk; ++i) res.push_back(rest[i]);\n        return res;\n    }\n\n    array<uint8_t, N> beam_search_row(const vector<int>& weight, const vector<uint8_t>& prefix, int BEAM = 120) {\n        if ((int)prefix.size() > N) return fallback_row(weight);\n\n        vector<BeamState> beam(1);\n        beam[0].node = 0;\n        beam[0].score = 0;\n        beam[0].seen.fill(0);\n\n        int pos = 0;\n        for (uint8_t c : prefix) {\n            beam[0].s[pos++] = c;\n            beam[0].node = ac[beam[0].node].next[c];\n            for (int id : ac[beam[0].node].out) {\n                if (weight[id] > 0 && !getbit(beam[0].seen, id)) {\n                    setbit(beam[0].seen, id);\n                    beam[0].score += weight[id];\n                }\n            }\n        }\n\n        for (int d = pos; d < N; ++d) {\n            vector<BeamState> cand;\n            cand.reserve(beam.size() * 8);\n\n            for (const auto& st : beam) {\n                for (int c = 0; c < 8; ++c) {\n                    BeamState ns = st;\n                    ns.s[d] = (uint8_t)c;\n                    ns.node = ac[st.node].next[c];\n                    for (int id : ac[ns.node].out) {\n                        if (weight[id] > 0 && !getbit(ns.seen, id)) {\n                            setbit(ns.seen, id);\n                            ns.score += weight[id];\n                        }\n                    }\n                    cand.push_back(std::move(ns));\n                }\n            }\n\n            auto cmp = [](const BeamState& a, const BeamState& b) {\n                return a.score > b.score;\n            };\n            if ((int)cand.size() > BEAM) {\n                nth_element(cand.begin(), cand.begin() + BEAM, cand.end(), cmp);\n                cand.resize(BEAM);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n            beam.swap(cand);\n        }\n\n        int best_gain = -1;\n        array<uint8_t, N> best_row{};\n        int take = min<int>(24, beam.size());\n        for (int i = 0; i < take; ++i) {\n            Bits bits{};\n            int g = row_gain_and_bits(beam[i].s, weight, bits);\n            if (g > best_gain) {\n                best_gain = g;\n                best_row = beam[i].s;\n            }\n        }\n        if (best_gain <= 0) return fallback_row(weight);\n        return best_row;\n    }\n\n    void add_candidate(vector<Candidate>& pool, unordered_set<string>& used, const array<uint8_t, N>& row) {\n        string canon = canonical_row(row);\n        if (!used.insert(canon).second) return;\n        Candidate c;\n        c.row = row;\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        c.bits = compute_bits_seq(seq);\n        c.canon = canon;\n        pool.push_back(std::move(c));\n    }\n\n    vector<Candidate> generate_candidate_pool() {\n        vector<Candidate> pool;\n        unordered_set<string> used;\n        used.reserve(512);\n\n        auto generate_with_scheme = [&](vector<int> residual, int rounds, int beamw) {\n            for (int t = 0; t < rounds; ++t) {\n                if (timer.elapsed() > 0.45) return;\n\n                vector<array<uint8_t, N>> cand_rows;\n                cand_rows.push_back(beam_search_row(residual, {}, beamw));\n\n                auto seeds = pick_seed_patterns(residual, 2, 1);\n                for (int id : seeds) {\n                    vector<uint8_t> pref;\n                    for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                    cand_rows.push_back(beam_search_row(residual, pref, beamw));\n                }\n\n                int best_gain = -1;\n                array<uint8_t, N> best_row{};\n                Bits best_bits{};\n\n                for (auto& row : cand_rows) {\n                    Bits bits{};\n                    int g = row_gain_and_bits(row, residual, bits);\n                    if (g > best_gain) {\n                        best_gain = g;\n                        best_row = row;\n                        best_bits = bits;\n                    }\n                }\n\n                add_candidate(pool, used, best_row);\n                for (int id = 0; id < K; ++id) if (getbit(best_bits, id)) residual[id] = 0;\n            }\n        };\n\n        vector<int> w1 = orig_weight;\n        generate_with_scheme(w1, 10, 120);\n\n        vector<int> w2(K);\n        for (int i = 0; i < K; ++i) w2[i] = orig_weight[i] * pats[i].len;\n        generate_with_scheme(w2, 10, 100);\n\n        vector<int> w3(K);\n        for (int i = 0; i < K; ++i) w3[i] = pats[i].len;\n        generate_with_scheme(w3, 8, 90);\n\n        vector<int> ids(K);\n        iota(ids.begin(), ids.end(), 0);\n        shuffle(ids.begin(), ids.end(), rng);\n        for (int z = 0; z < min(10, K) && timer.elapsed() <= 0.52; ++z) {\n            int id = ids[z];\n            vector<uint8_t> pref;\n            for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n            auto row = beam_search_row(orig_weight, pref, 90);\n            add_candidate(pool, used, row);\n        }\n\n        if (pool.empty()) add_candidate(pool, used, fallback_row(orig_weight));\n        return pool;\n    }\n\n    vector<array<uint8_t, N>> select_rows_trial(const vector<Candidate>& pool, int mode) {\n        vector<array<uint8_t, N>> rows;\n        vector<int> residual = orig_weight;\n        vector<int> used(pool.size(), 0);\n\n        for (int it = 0; it < N; ++it) {\n            int best = -1;\n            double best_score = -1e100;\n            for (int i = 0; i < (int)pool.size(); ++i) {\n                if (used[i]) continue;\n                int g = gain_by_bits(pool[i].bits, residual);\n                double score = g;\n                if (mode == 1) score += uniform_real_distribution<double>(0.0, 3.0)(rng);\n                if (mode == 2) score += uniform_real_distribution<double>(0.0, 10.0)(rng);\n                if (score > best_score) {\n                    best_score = score;\n                    best = i;\n                }\n            }\n            if (best == -1 || best_score <= 0) {\n                auto row = fallback_row(residual);\n                rows.push_back(row);\n                Bits bits{};\n                row_gain_and_bits(row, residual, bits);\n                for (int id = 0; id < K; ++id) if (getbit(bits, id)) residual[id] = 0;\n            } else {\n                used[best] = 1;\n                rows.push_back(pool[best].row);\n                for (int id = 0; id < K; ++id) if (getbit(pool[best].bits, id)) residual[id] = 0;\n            }\n        }\n        return rows;\n    }\n\n    void init_matrix_state(MatrixState& ms, const vector<array<uint8_t, N>>& rows) {\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ms.a[r][c] = rows[r][c];\n\n        for (int r = 0; r < N; ++r) ms.row_bits[r] = compute_row_bits(ms, r);\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = compute_col_bits(ms, c);\n\n        ms.cnt.assign(K, 0);\n        for (int r = 0; r < N; ++r)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.row_bits[r], id)) ms.cnt[id]++;\n\n        for (int c = 0; c < N; ++c)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.col_bits[c], id)) ms.cnt[id]++;\n\n        ms.score = 0;\n        for (int id = 0; id < K; ++id) if (ms.cnt[id] > 0) ms.score += orig_weight[id];\n    }\n\n    void transpose_state(MatrixState& ms) {\n        for (int i = 0; i < N; ++i)\n            for (int j = i + 1; j < N; ++j)\n                swap(ms.a[i][j], ms.a[j][i]);\n        swap(ms.row_bits, ms.col_bits);\n    }\n\n    int eval_row_replace(const MatrixState& ms, int r,\n                         const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                         array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) seq[i] = (i == r ? new_row[c] : ms.a[i][c]);\n            new_cols[c] = compute_bits_seq(seq);\n        }\n\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_row_replace(MatrixState& ms, int r,\n                           const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                           const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n\n        for (int c = 0; c < N; ++c) ms.a[r][c] = new_row[c];\n        ms.row_bits[r] = new_row_bits;\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = new_cols[c];\n        ms.score += delta;\n    }\n\n    bool same_exact_row(const MatrixState& ms, int r, const array<uint8_t, N>& row) const {\n        for (int c = 0; c < N; ++c) if (ms.a[r][c] != row[c]) return false;\n        return true;\n    }\n\n    bool improve_rows_from_pool(MatrixState& ms, const vector<Candidate>& pool, double time_limit) {\n        bool improved_any = false;\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int t = 0; t < N; ++t) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[t];\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            auto test_base = [&](const array<uint8_t, N>& base_row, const Bits& base_bits) {\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base_row[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, base_bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = base_bits;\n                        best_cols = new_cols;\n                    }\n                }\n            };\n\n            for (const auto& cand : pool) test_base(cand.row, cand.bits);\n            for (int i = 0; i < N; ++i) {\n                array<uint8_t, N> cur{};\n                for (int c = 0; c < N; ++c) cur[c] = ms.a[i][c];\n                test_base(cur, ms.row_bits[i]);\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved_any = true;\n            }\n        }\n        return improved_any;\n    }\n\n    bool dynamic_rebuild_rows(MatrixState& ms, double time_limit) {\n        bool improved = false;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int ii = 0; ii < N; ++ii) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[ii];\n\n            // Weight patterns that are currently uncovered, or only this row supports.\n            vector<int> w(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) {\n                    w[id] = orig_weight[id] * 4;\n                } else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) {\n                    w[id] = orig_weight[id] * 2;\n                }\n            }\n\n            int sumw = 0;\n            for (int x : w) sumw += x;\n            if (sumw == 0) continue;\n\n            vector<array<uint8_t, N>> cand_rows;\n            cand_rows.push_back(beam_search_row(w, {}, 120));\n\n            auto seeds = pick_seed_patterns(w, 3, 1);\n            for (int id : seeds) {\n                vector<uint8_t> pref;\n                for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                cand_rows.push_back(beam_search_row(w, pref, 100));\n            }\n\n            // also a milder weight to avoid too narrow rebuilds\n            vector<int> w2(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) w2[id] = orig_weight[id];\n                else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) w2[id] = orig_weight[id];\n            }\n            cand_rows.push_back(beam_search_row(w2, {}, 90));\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            for (auto& base : cand_rows) {\n                Bits bits{};\n                uint8_t seq[N];\n                for (int c = 0; c < N; ++c) seq[c] = base[c];\n                bits = compute_bits_seq(seq);\n\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = bits;\n                        best_cols = new_cols;\n                    }\n                }\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    int eval_row_swap(const MatrixState& ms, int r1, int r2, array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                if (i == r1) seq[i] = ms.a[r2][c];\n                else if (i == r2) seq[i] = ms.a[r1][c];\n                else seq[i] = ms.a[i][c];\n            }\n            new_cols[c] = compute_bits_seq(seq);\n        }\n\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_row_swap(MatrixState& ms, int r1, int r2, const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n        swap(ms.a[r1], ms.a[r2]);\n        swap(ms.row_bits[r1], ms.row_bits[r2]);\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = new_cols[c];\n        ms.score += delta;\n    }\n\n    int eval_col_swap(const MatrixState& ms, int c1, int c2, array<Bits, N>& new_rows) const {\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                if (j == c1) seq[j] = ms.a[r][c2];\n                else if (j == c2) seq[j] = ms.a[r][c1];\n                else seq[j] = ms.a[r][j];\n            }\n            new_rows[r] = compute_bits_seq(seq);\n        }\n\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_col_swap(MatrixState& ms, int c1, int c2, const array<Bits, N>& new_rows, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            ms.cnt[id] = after;\n        }\n        for (int r = 0; r < N; ++r) swap(ms.a[r][c1], ms.a[r][c2]);\n        swap(ms.col_bits[c1], ms.col_bits[c2]);\n        for (int r = 0; r < N; ++r) ms.row_bits[r] = new_rows[r];\n        ms.score += delta;\n    }\n\n    void swap_hill_climb(MatrixState& ms, double time_limit) {\n        while (timer.elapsed() < time_limit) {\n            int best_delta = 0;\n            int best_type = -1, best_a = -1, best_b = -1;\n            array<Bits, N> best_lines{};\n\n            for (int r1 = 0; r1 < N; ++r1) {\n                for (int r2 = r1 + 1; r2 < N; ++r2) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_swap(ms, r1, r2, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 0;\n                        best_a = r1;\n                        best_b = r2;\n                        best_lines = new_cols;\n                    }\n                }\n            }\n\n            for (int c1 = 0; c1 < N; ++c1) {\n                for (int c2 = c1 + 1; c2 < N; ++c2) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_swap(ms, c1, c2, new_rows);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_type = 1;\n                        best_a = c1;\n                        best_b = c2;\n                        best_lines = new_rows;\n                    }\n                }\n            }\n\n            if (best_delta <= 0) break;\n            if (best_type == 0) apply_row_swap(ms, best_a, best_b, best_lines, best_delta);\n            else apply_col_swap(ms, best_a, best_b, best_lines, best_delta);\n        }\n    }\n\n    int calc_delta_two(const MatrixState& ms, const Bits& old1, const Bits& new1,\n                       const Bits& old2, const Bits& new2) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before\n                      - (int)getbit(old1, id)\n                      - (int)getbit(old2, id)\n                      + (int)getbit(new1, id)\n                      + (int)getbit(new2, id);\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_two(MatrixState& ms, const Bits& old1, const Bits& new1,\n                   const Bits& old2, const Bits& new2) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(old1, id);\n            after -= (int)getbit(old2, id);\n            after += (int)getbit(new1, id);\n            after += (int)getbit(new2, id);\n            ms.cnt[id] = after;\n        }\n    }\n\n    void cell_local_search(MatrixState& ms, double time_limit) {\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        auto bestA = ms.a;\n        int bestScore = ms.score;\n\n        while (timer.elapsed() < time_limit) {\n            double prog = timer.elapsed() / time_limit;\n            double T = 1.2 * pow(0.02 / 1.2, prog);\n\n            int r = (int)(rng() % N);\n            int c = (int)(rng() % N);\n            uint8_t oldch = ms.a[r][c];\n\n            Bits oldR = ms.row_bits[r];\n            Bits oldC = ms.col_bits[c];\n\n            int best_delta = -1e9;\n            uint8_t best_ch = oldch;\n            Bits bestR = oldR, bestC = oldC;\n\n            for (uint8_t ch = 0; ch < 8; ++ch) {\n                if (ch == oldch) continue;\n                ms.a[r][c] = ch;\n                Bits newR = compute_row_bits(ms, r);\n                Bits newC = compute_col_bits(ms, c);\n                int delta = calc_delta_two(ms, oldR, newR, oldC, newC);\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_ch = ch;\n                    bestR = newR;\n                    bestC = newC;\n                }\n            }\n\n            bool accept = false;\n            if (best_delta >= 0) accept = true;\n            else if (urd(rng) < exp((double)best_delta / T)) accept = true;\n\n            if (accept && best_ch != oldch) {\n                ms.a[r][c] = best_ch;\n                apply_two(ms, oldR, bestR, oldC, bestC);\n                ms.row_bits[r] = bestR;\n                ms.col_bits[c] = bestC;\n                ms.score += best_delta;\n                if (ms.score > bestScore) {\n                    bestScore = ms.score;\n                    bestA = ms.a;\n                }\n            } else {\n                ms.a[r][c] = oldch;\n            }\n        }\n\n        ms.a = bestA;\n    }\n\n    vector<string> solve() {\n        int n;\n        cin >> n >> M;\n\n        array<unordered_map<uint64_t, int>, MAXL + 1> cnt_of;\n        for (int len = MINL; len <= MAXL; ++len) cnt_of[len].reserve(M * 2);\n\n        for (int i = 0; i < M; ++i) {\n            string s;\n            cin >> s;\n            cnt_of[(int)s.size()][encode_string(s)]++;\n        }\n\n        pats.clear();\n        for (int len = MINL; len <= MAXL; ++len) {\n            id_of[len].clear();\n            id_of[len].reserve(cnt_of[len].size() * 2 + 1);\n            for (auto& kv : cnt_of[len]) {\n                Pattern p;\n                p.len = len;\n                p.code = kv.first;\n                p.weight = kv.second;\n                p.s = decode_string(kv.first, len);\n                int id = (int)pats.size();\n                pats.push_back(std::move(p));\n                id_of[len][kv.first] = id;\n            }\n        }\n\n        K = (int)pats.size();\n        orig_weight.assign(K, 0);\n        for (int i = 0; i < K; ++i) orig_weight[i] = pats[i].weight;\n\n        build_ac();\n\n        auto pool = generate_candidate_pool();\n\n        // Multiple initial selections, choose best by exact score.\n        MatrixState best_ms;\n        int best_init_score = -1;\n\n        for (int trial = 0; trial < 3; ++trial) {\n            auto rows = select_rows_trial(pool, trial);\n            MatrixState ms;\n            init_matrix_state(ms, rows);\n            if (ms.score > best_init_score) {\n                best_init_score = ms.score;\n                best_ms = ms;\n            }\n        }\n\n        MatrixState ms = best_ms;\n\n        if (timer.elapsed() < 1.00) improve_rows_from_pool(ms, pool, 1.00);\n        if (timer.elapsed() < 1.60) dynamic_rebuild_rows(ms, 1.60);\n\n        if (timer.elapsed() < 2.05) {\n            transpose_state(ms);\n            improve_rows_from_pool(ms, pool, 2.05);\n        }\n        if (timer.elapsed() < 2.40) {\n            dynamic_rebuild_rows(ms, 2.40);\n            transpose_state(ms);\n        } else {\n            transpose_state(ms);\n        }\n\n        if (timer.elapsed() < 2.60) swap_hill_climb(ms, 2.60);\n        if (timer.elapsed() < 2.95 && ms.score < M) cell_local_search(ms, 2.95);\n\n        vector<string> ans(N, string(N, 'A'));\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ans[r][c] = v2ch(ms.a[r][c]);\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    auto ans = solver.solve();\n    for (auto& s : ans) cout << s << '\\n';\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\n\nstruct Dinic {\n    struct Edge {\n        int to, rev;\n        ll cap;\n    };\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic() {}\n    Dinic(int n) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, ll 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\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();\n            q.pop();\n            for (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\n    ll dfs(int v, int t, ll 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[v] >= level[e.to]) continue;\n            ll d = dfs(e.to, t, min(f, e.cap));\n            if (d <= 0) continue;\n            e.cap -= d;\n            g[e.to][e.rev].cap += d;\n            return d;\n        }\n        return 0;\n    }\n\n    ll maxflow(int s, int t) {\n        ll flow = 0;\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n            while (true) {\n                ll f = dfs(s, t, INF64);\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n\n    vector<char> reachable_from(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();\n            q.pop();\n            for (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\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    cin >> N >> si >> sj;\n    vector<string> c(N);\n    for (int i = 0; i < N; i++) cin >> c[i];\n\n    // Enumerate road cells\n    vector<vector<int>> cellId(N, vector<int>(N, -1));\n    vector<int> rr, cc, enterCost;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (c[i][j] != '#') {\n                cellId[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                enterCost.push_back(c[i][j] - '0');\n            }\n        }\n    }\n    int M = (int)rr.size();\n    int startCell = cellId[si][sj];\n\n    // Cell graph\n    vector<vector<int>> nbr(M);\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (0 <= ni && ni < N && 0 <= nj && nj < N && cellId[ni][nj] != -1) {\n                nbr[id].push_back(cellId[ni][nj]);\n            }\n        }\n    }\n\n    auto dijkstra = [&](int src, bool reverse, bool needPrev) {\n        vector<ll> dist(M, INF64);\n        vector<int> prev(needPrev ? M : 0, -1);\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n        while (!pq.empty()) {\n            auto [cd, u] = pq.top();\n            pq.pop();\n            if (cd != dist[u]) continue;\n            for (int v : nbr[u]) {\n                ll w = reverse ? enterCost[u] : enterCost[v];\n                ll nd = cd + w;\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (needPrev) prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n        return pair<vector<ll>, vector<int>>(move(dist), move(prev));\n    };\n\n    auto [distFromStart, _d0] = dijkstra(startCell, false, false);\n    auto [distToStart, _d1] = dijkstra(startCell, true, false);\n\n    // Segment decomposition\n    vector<vector<int>> hSeg(N, vector<int>(N, -1));\n    vector<vector<int>> vSeg(N, vector<int>(N, -1));\n    int Hcnt = 0, Vcnt = 0;\n\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (c[i][j] == '#') {\n                j++;\n                continue;\n            }\n            int k = j;\n            while (k < N && c[i][k] != '#') {\n                hSeg[i][k] = Hcnt;\n                k++;\n            }\n            Hcnt++;\n            j = k;\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (c[i][j] == '#') {\n                i++;\n                continue;\n            }\n            int k = i;\n            while (k < N && c[k][j] != '#') {\n                vSeg[k][j] = Vcnt;\n                k++;\n            }\n            Vcnt++;\n            i = k;\n        }\n    }\n\n    vector<int> cellH(M), cellV(M);\n    vector<vector<int>> cellsOfH(Hcnt), cellsOfV(Vcnt);\n    vector<vector<int>> adjV(Hcnt);\n    vector<vector<int>> adjCellH(Hcnt);\n\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        int h = hSeg[i][j];\n        int v = vSeg[i][j];\n        cellH[id] = h;\n        cellV[id] = v;\n        cellsOfH[h].push_back(id);\n        cellsOfV[v].push_back(id);\n        adjV[h].push_back(v);\n        adjCellH[h].push_back(id);\n    }\n\n    int startH = cellH[startCell];\n    int startV = cellV[startCell];\n\n    auto cellRoundTrip = [&](int id) -> ll {\n        return distFromStart[id] + distToStart[id];\n    };\n\n    // Weighted minimum vertex cover on segment bipartite graph\n    vector<ll> wH(Hcnt, INF64), wV(Vcnt, INF64);\n    for (int id = 0; id < M; id++) {\n        ll w = cellRoundTrip(id);\n        wH[cellH[id]] = min(wH[cellH[id]], w);\n        wV[cellV[id]] = min(wV[cellV[id]], w);\n    }\n    wH[startH] = 0;\n    wV[startV] = 0;\n\n    vector<char> selH(Hcnt, 0), selV(Vcnt, 0);\n    {\n        int S = Hcnt + Vcnt;\n        int T = S + 1;\n        Dinic mf(Hcnt + Vcnt + 2);\n        ll sumW = 0;\n        for (int h = 0; h < Hcnt; h++) {\n            mf.add_edge(S, h, wH[h]);\n            sumW += wH[h];\n        }\n        for (int v = 0; v < Vcnt; v++) {\n            mf.add_edge(Hcnt + v, T, wV[v]);\n            sumW += wV[v];\n        }\n        ll BIG = max<ll>((ll)1e15, sumW + 1);\n        for (int h = 0; h < Hcnt; h++) {\n            for (int v : adjV[h]) mf.add_edge(h, Hcnt + v, BIG);\n        }\n        mf.maxflow(S, T);\n        vector<char> reach = mf.reachable_from(S);\n        for (int h = 0; h < Hcnt; h++) selH[h] = !reach[h];\n        for (int v = 0; v < Vcnt; v++) selV[v] = reach[Hcnt + v];\n    }\n\n    // Start already activates its own segments\n    vector<char> needH = selH, needV = selV;\n    needH[startH] = 0;\n    needV[startV] = 0;\n\n    // Greedy watch-cell selection\n    vector<char> chosenCell(M, 0);\n    int remainH = 0, remainV = 0;\n    for (int h = 0; h < Hcnt; h++) if (needH[h]) remainH++;\n    for (int v = 0; v < Vcnt; v++) if (needV[v]) remainV++;\n\n    while (remainH > 0 || remainV > 0) {\n        int bestCell = -1;\n        ll bestCost = INF64;\n        int bestBenefit = -1;\n\n        for (int id = 0; id < M; id++) {\n            int h = cellH[id], v = cellV[id];\n            int benefit = (needH[h] ? 1 : 0) + (needV[v] ? 1 : 0);\n            if (benefit == 0) continue;\n            ll cost = cellRoundTrip(id);\n\n            if (bestCell == -1) {\n                bestCell = id;\n                bestCost = cost;\n                bestBenefit = benefit;\n            } else {\n                __int128 lhs = (__int128)cost * bestBenefit;\n                __int128 rhs = (__int128)bestCost * benefit;\n                bool better = false;\n                if (lhs != rhs) better = lhs < rhs;\n                else if (benefit != bestBenefit) better = benefit > bestBenefit;\n                else if (cost != bestCost) better = cost < bestCost;\n                else if (rr[id] != rr[bestCell]) better = rr[id] < rr[bestCell];\n                else better = cc[id] < cc[bestCell];\n                if (better) {\n                    bestCell = id;\n                    bestCost = cost;\n                    bestBenefit = benefit;\n                }\n            }\n        }\n\n        if (bestCell == -1) break; // should not happen\n\n        chosenCell[bestCell] = 1;\n        int h = cellH[bestCell], v = cellV[bestCell];\n        if (needH[h]) {\n            needH[h] = 0;\n            remainH--;\n        }\n        if (needV[v]) {\n            needV[v] = 0;\n            remainV--;\n        }\n    }\n\n    // Remove redundant chosen cells while preserving selected-segment activation\n    vector<int> chosenList;\n    for (int id = 0; id < M; id++) if (chosenCell[id]) chosenList.push_back(id);\n\n    vector<int> cntSelH(Hcnt, 0), cntSelV(Vcnt, 0);\n    if (selH[startH]) cntSelH[startH]++;\n    if (selV[startV]) cntSelV[startV]++;\n    for (int id : chosenList) {\n        if (selH[cellH[id]]) cntSelH[cellH[id]]++;\n        if (selV[cellV[id]]) cntSelV[cellV[id]]++;\n    }\n\n    sort(chosenList.begin(), chosenList.end(), [&](int a, int b) {\n        ll wa = cellRoundTrip(a), wb = cellRoundTrip(b);\n        if (wa != wb) return wa > wb;\n        if (rr[a] != rr[b]) return rr[a] < rr[b];\n        return cc[a] < cc[b];\n    });\n\n    for (int id : chosenList) {\n        if (!chosenCell[id]) continue;\n        int h = cellH[id], v = cellV[id];\n        bool ok = true;\n        if (selH[h] && cntSelH[h] <= 1) ok = false;\n        if (selV[v] && cntSelV[v] <= 1) ok = false;\n        if (ok) {\n            chosenCell[id] = 0;\n            if (selH[h]) cntSelH[h]--;\n            if (selV[v]) cntSelV[v]--;\n        }\n    }\n\n    // Waypoints = start + chosen cells\n    vector<int> relCells;\n    relCells.push_back(startCell);\n    for (int id = 0; id < M; id++) {\n        if (chosenCell[id] && id != startCell) relCells.push_back(id);\n    }\n    int R = (int)relCells.size();\n\n    // Distances / predecessors from each waypoint\n    vector<vector<ll>> distMat(R, vector<ll>(R, INF64));\n    vector<vector<int>> prevs(R, vector<int>(M, -1));\n    for (int s = 0; s < R; s++) {\n        auto [dist, prev] = dijkstra(relCells[s], false, true);\n        prevs[s] = move(prev);\n        for (int t = 0; t < R; t++) distMat[s][t] = dist[relCells[t]];\n    }\n\n    auto cycleCost = [&](const vector<int>& cyc) -> ll {\n        int sz = (int)cyc.size();\n        ll ret = 0;\n        for (int i = 0; i < sz; i++) {\n            ret += distMat[cyc[i]][cyc[(i + 1) % sz]];\n        }\n        return ret;\n    };\n\n    // Initial route: cheapest insertion\n    vector<int> cycle;\n    if (R == 1) {\n        cycle = {0};\n    } else {\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestInit = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll v = distMat[0][i] + distMat[i][0];\n            if (v < bestInit) {\n                bestInit = v;\n                first = i;\n            }\n        }\n        cycle = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            ll bestDelta = INF64;\n            int bestNode = -1, bestPos = -1;\n            int sz = (int)cycle.size();\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                for (int pos = 0; pos < sz; pos++) {\n                    int a = cycle[pos];\n                    int b = cycle[(pos + 1) % sz];\n                    ll delta = distMat[a][x] + distMat[x][b] - distMat[a][b];\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestNode = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            used[bestNode] = 1;\n            cycle.insert(cycle.begin() + bestPos + 1, bestNode);\n        }\n\n        // Local search: relocate + swap\n        for (int phase = 0; phase < 3; phase++) {\n            bool improved = true;\n            while (improved) {\n                improved = false;\n                int sz = (int)cycle.size();\n\n                // Relocate\n                for (int i = 1; i < sz && !improved; i++) {\n                    int x = cycle[i];\n                    int a = cycle[(i - 1 + sz) % sz];\n                    int b = cycle[(i + 1) % sz];\n                    ll rem = distMat[a][b] - distMat[a][x] - distMat[x][b];\n\n                    for (int j = 0; j < sz && !improved; j++) {\n                        if (j == i || j == (i - 1 + sz) % sz) continue;\n                        int c1 = cycle[j];\n                        int d1 = cycle[(j + 1) % sz];\n                        ll add = distMat[c1][x] + distMat[x][d1] - distMat[c1][d1];\n                        if (rem + add < 0) {\n                            cycle.erase(cycle.begin() + i);\n                            if (j > i) j--;\n                            cycle.insert(cycle.begin() + j + 1, x);\n                            improved = true;\n                        }\n                    }\n                }\n                if (improved) continue;\n\n                // Swap\n                sz = (int)cycle.size();\n                ll curCost = cycleCost(cycle);\n                for (int i = 1; i < sz && !improved; i++) {\n                    for (int j = i + 1; j < sz && !improved; j++) {\n                        vector<int> nc = cycle;\n                        swap(nc[i], nc[j]);\n                        ll ncCost = cycleCost(nc);\n                        if (ncCost < curCost) {\n                            cycle.swap(nc);\n                            curCost = ncCost;\n                            improved = true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Precompute path-segment coverage for each directed arc waypoint s -> t\n    int RR = R;\n    vector<vector<int>> arcHs(RR * RR), arcVs(RR * RR);\n    vector<int> seenH(Hcnt, -1), seenV(Vcnt, -1);\n    int stamp = 0;\n\n    auto build_arc_coverage = [&](int s, int t) {\n        int idx = s * RR + t;\n        stamp++;\n\n        vector<int> pathCells;\n        int srcCell = relCells[s];\n        int dstCell = relCells[t];\n\n        pathCells.push_back(srcCell);\n        if (srcCell != dstCell) {\n            vector<int> rev;\n            int cur = dstCell;\n            while (cur != srcCell) {\n                int p = prevs[s][cur];\n                if (p == -1) break;\n                rev.push_back(cur);\n                cur = p;\n            }\n            reverse(rev.begin(), rev.end());\n            for (int x : rev) pathCells.push_back(x);\n        }\n\n        auto &hs = arcHs[idx];\n        auto &vs = arcVs[idx];\n        hs.clear();\n        vs.clear();\n\n        for (int cell : pathCells) {\n            int h = cellH[cell], v = cellV[cell];\n            if (seenH[h] != stamp) {\n                seenH[h] = stamp;\n                hs.push_back(h);\n            }\n            if (seenV[v] != stamp) {\n                seenV[v] = stamp;\n                vs.push_back(v);\n            }\n        }\n    };\n\n    for (int s = 0; s < RR; s++) {\n        for (int t = 0; t < RR; t++) {\n            build_arc_coverage(s, t);\n        }\n    }\n\n    auto add_arc_cov = [&](vector<int>& cntH2, vector<int>& cntV2, int a, int b, int delta) {\n        int idx = a * RR + b;\n        for (int h : arcHs[idx]) cntH2[h] += delta;\n        for (int v : arcVs[idx]) cntV2[v] += delta;\n    };\n\n    auto full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2) -> bool {\n        for (int id = 0; id < M; id++) {\n            if (cntH2[cellH[id]] == 0 && cntV2[cellV[id]] == 0) return false;\n        }\n        return true;\n    };\n\n    // Coverage-preserving waypoint deletion\n    vector<int> covH(Hcnt, 0), covV(Vcnt, 0);\n    {\n        int sz = (int)cycle.size();\n        for (int i = 0; i < sz; i++) {\n            int a = cycle[i];\n            int b = cycle[(i + 1) % sz];\n            add_arc_cov(covH, covV, a, b, +1);\n        }\n    }\n\n    while ((int)cycle.size() > 1) {\n        int sz = (int)cycle.size();\n        int bestPos = -1;\n        ll bestDelta = 0;\n\n        for (int pos = 1; pos < sz; pos++) { // never delete start waypoint\n            int a = cycle[(pos - 1 + sz) % sz];\n            int b = cycle[pos];\n            int c2 = cycle[(pos + 1) % sz];\n            ll delta = distMat[a][c2] - distMat[a][b] - distMat[b][c2];\n\n            add_arc_cov(covH, covV, a, b, -1);\n            add_arc_cov(covH, covV, b, c2, -1);\n            add_arc_cov(covH, covV, a, c2, +1);\n\n            bool ok = full_covered(covH, covV);\n\n            add_arc_cov(covH, covV, a, c2, -1);\n            add_arc_cov(covH, covV, a, b, +1);\n            add_arc_cov(covH, covV, b, c2, +1);\n\n            if (ok && delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = pos;\n            }\n        }\n\n        if (bestPos == -1) break;\n\n        int a = cycle[(bestPos - 1 + sz) % sz];\n        int b = cycle[bestPos];\n        int c2 = cycle[(bestPos + 1) % sz];\n\n        add_arc_cov(covH, covV, a, b, -1);\n        add_arc_cov(covH, covV, b, c2, -1);\n        add_arc_cov(covH, covV, a, c2, +1);\n\n        cycle.erase(cycle.begin() + bestPos);\n    }\n\n    // Build full cell-by-cell route\n    vector<int> path;\n    path.push_back(startCell);\n    for (int idx = 0; idx < (int)cycle.size(); idx++) {\n        int s = cycle[idx];\n        int t = cycle[(idx + 1) % cycle.size()];\n        int sCell = relCells[s];\n        int tCell = relCells[t];\n        if (sCell == tCell) continue;\n\n        vector<int> rev;\n        int cur = tCell;\n        while (cur != sCell) {\n            int p = prevs[s][cur];\n            if (p == -1) break;\n            rev.push_back(cur);\n            cur = p;\n        }\n        reverse(rev.begin(), rev.end());\n        for (int x : rev) path.push_back(x);\n    }\n\n    // Safe final exact loop deletion on the full path\n    auto path_full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2,\n                                 const vector<int>& touchedCells) -> bool {\n        for (int cell : touchedCells) {\n            if (cntH2[cellH[cell]] == 0 && cntV2[cellV[cell]] == 0) return false;\n        }\n        return true;\n    };\n\n    vector<int> cntPathH(Hcnt, 0), cntPathV(Vcnt, 0);\n    for (int cell : path) {\n        cntPathH[cellH[cell]]++;\n        cntPathV[cellV[cell]]++;\n    }\n\n    vector<int> markH(Hcnt, -1), markV(Vcnt, -1), markCell(M, -1);\n    vector<int> decH(Hcnt, 0), decV(Vcnt, 0);\n    int stamp2 = 0;\n\n    while (true) {\n        int L = (int)path.size();\n        if (L <= 1) break;\n\n        vector<ll> pref(L, 0);\n        for (int i = 1; i < L; i++) pref[i] = pref[i - 1] + enterCost[path[i]];\n\n        vector<vector<int>> occ(M);\n        ll bestSave = 0;\n        int bestL = -1, bestR = -1;\n\n        for (int p = 0; p < L; p++) {\n            int cell = path[p];\n            auto &vec = occ[cell];\n\n            int checks = 0;\n            for (int z = (int)vec.size() - 1; z >= 0 && checks < 8; z--, checks++) {\n                int l = vec[z];\n                if (p <= l) continue;\n                ll save = pref[p] - pref[l];\n                if (save <= bestSave) continue;\n\n                stamp2++;\n                vector<int> touchedHs, touchedVs, touchedCells;\n\n                for (int q = l + 1; q <= p; q++) {\n                    int x = path[q];\n                    int h = cellH[x], v = cellV[x];\n\n                    if (markH[h] != stamp2) {\n                        markH[h] = stamp2;\n                        decH[h] = 0;\n                        touchedHs.push_back(h);\n                    }\n                    if (markV[v] != stamp2) {\n                        markV[v] = stamp2;\n                        decV[v] = 0;\n                        touchedVs.push_back(v);\n                    }\n                    decH[h]++;\n                    decV[v]++;\n\n                    if (markCell[x] != stamp2) {\n                        markCell[x] = stamp2;\n                        touchedCells.push_back(x);\n                    }\n                }\n\n                for (int h : touchedHs) cntPathH[h] -= decH[h];\n                for (int v : touchedVs) cntPathV[v] -= decV[v];\n\n                // Only cells whose H or V was touched can change coverage.\n                // touchedCells already covers all cells on removed loop.\n                // But we also need cells on the same touched segments.\n                for (int h : touchedHs) {\n                    for (int cell2 : cellsOfH[h]) {\n                        if (markCell[cell2] != stamp2) {\n                            markCell[cell2] = stamp2;\n                            touchedCells.push_back(cell2);\n                        }\n                    }\n                }\n                for (int v : touchedVs) {\n                    for (int cell2 : cellsOfV[v]) {\n                        if (markCell[cell2] != stamp2) {\n                            markCell[cell2] = stamp2;\n                            touchedCells.push_back(cell2);\n                        }\n                    }\n                }\n\n                bool ok = path_full_covered(cntPathH, cntPathV, touchedCells);\n\n                for (int h : touchedHs) cntPathH[h] += decH[h];\n                for (int v : touchedVs) cntPathV[v] += decV[v];\n\n                if (ok) {\n                    bestSave = save;\n                    bestL = l;\n                    bestR = p;\n                }\n            }\n\n            vec.push_back(p);\n        }\n\n        if (bestSave <= 0) break;\n\n        for (int q = bestL + 1; q <= bestR; q++) {\n            int x = path[q];\n            cntPathH[cellH[x]]--;\n            cntPathV[cellV[x]]--;\n        }\n        path.erase(path.begin() + bestL + 1, path.begin() + bestR + 1);\n    }\n\n    auto dirChar = [&](int a, int b) -> char {\n        int ra = rr[a], ca = cc[a];\n        int rb = rr[b], cb = cc[b];\n        if (rb == ra - 1 && cb == ca) return 'U';\n        if (rb == ra + 1 && cb == ca) return 'D';\n        if (rb == ra && cb == ca - 1) return 'L';\n        return 'R';\n    };\n\n    string ans;\n    for (int i = 1; i < (int)path.size(); i++) {\n        ans.push_back(dirChar(path[i - 1], path[i]));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 1000;\n\nstruct Observation {\n    int task;\n    int t;\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>> children(N), parents(N);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        children[u].push_back(v);\n        parents[v].push_back(u);\n    }\n\n    // ----------------------------\n    // Precompute task statistics\n    // ----------------------------\n    vector<int> indeg(N), rem_pre(N), outdeg(N, 0), sumd(N, 0);\n    vector<int> maxd(K, 0);\n    vector<double> avgd(K, 0.0);\n\n    for (int i = 0; i < N; ++i) {\n        indeg[i] = (int)parents[i].size();\n        rem_pre[i] = indeg[i];\n        outdeg[i] = (int)children[i].size();\n        for (int k = 0; k < K; ++k) {\n            sumd[i] += d[i][k];\n            maxd[k] = max(maxd[k], d[i][k]);\n            avgd[k] += d[i][k];\n        }\n    }\n    for (int k = 0; k < K; ++k) avgd[k] /= N;\n\n    // Initial skill guess.\n    // Members are generated with larger norm than tasks on average,\n    // so slightly optimistic initialization is reasonable.\n    vector<int> init_skill(K);\n    for (int k = 0; k < K; ++k) {\n        int v = (int)llround(avgd[k] * 1.6);\n        v = max(0, min(v, maxd[k]));\n        init_skill[k] = v;\n    }\n\n    // Descendant count by bitset DP\n    vector<bitset<MAXN>> reach(N);\n    vector<int> desc_cnt(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        for (int ch : children[i]) {\n            reach[i] |= reach[ch];\n            reach[i].set(ch);\n        }\n        desc_cnt[i] = (int)reach[i].count();\n    }\n\n    // Weighted bottom level (longest weighted path to sink)\n    vector<long long> bottom(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        long long best_child = 0;\n        for (int ch : children[i]) best_child = max(best_child, bottom[ch]);\n        long long node_w = sumd[i] + 5;\n        bottom[i] = node_w + best_child;\n    }\n\n    // Static priority\n    vector<long long> base_priority(N, 0);\n    for (int i = 0; i < N; ++i) {\n        base_priority[i] =\n            bottom[i] * 30LL +\n            desc_cnt[i] * 5LL +\n            outdeg[i] * 20LL +\n            sumd[i];\n    }\n\n    auto calc_w_with_skill = [&](int task, const vector<int>& skill) -> int {\n        int w = 0;\n        for (int k = 0; k < K; ++k) {\n            if (d[task][k] > skill[k]) w += d[task][k] - skill[k];\n        }\n        return w;\n    };\n\n    vector<int> default_w(N), default_t(N);\n    for (int i = 0; i < N; ++i) {\n        default_w[i] = calc_w_with_skill(i, init_skill);\n        default_t[i] = max(1, default_w[i]);\n    }\n\n    // ----------------------------\n    // Online state\n    // ----------------------------\n    // -1: not started, 0: in progress, 1: completed\n    vector<int> task_status(N, -1);\n\n    // current task of each member\n    vector<int> current_task(M, -1);\n    vector<int> start_day(M, -1);\n\n    // estimated skills\n    vector<vector<int>> skill_hat(M, init_skill);\n    vector<vector<Observation>> obs(M);\n\n    auto loss_interval = [&](int w, int t) -> double {\n        int L, U;\n        if (t <= 1) {\n            // t=1 can happen for w up to 4 (e.g. w=4, r=-3)\n            L = 0;\n            U = 4;\n        } else {\n            L = max(0, t - 3);\n            U = t + 3;\n        }\n        double dist = 0.0;\n        if (w < L) dist = (double)(L - w);\n        else if (w > U) dist = (double)(w - U);\n        else dist = 0.0;\n\n        double weight = (t <= 1 ? 1.0 : 1.0 + 0.05 * min(t, 20));\n        return dist * dist * weight;\n    };\n\n    auto optimize_member = [&](int j) {\n        int T = (int)obs[j].size();\n        if (T == 0) return;\n\n        vector<int>& s = skill_hat[j];\n        vector<int> curW(T);\n        for (int idx = 0; idx < T; ++idx) {\n            curW[idx] = calc_w_with_skill(obs[j][idx].task, s);\n        }\n\n        const int max_iter = 3;\n        for (int it = 0; it < max_iter; ++it) {\n            bool changed = false;\n\n            for (int k = 0; k < K; ++k) {\n                int prev = s[k];\n\n                vector<int> base(T);\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    base[idx] = curW[idx] - max(0, d[task][k] - prev);\n                }\n\n                double best_obj = 1e100;\n                int best_x = prev;\n                int best_tie1 = 0;\n                int best_tie2 = abs(prev - init_skill[k]);\n\n                for (int x = 0; x <= maxd[k]; ++x) {\n                    double obj = 0.0;\n                    for (int idx = 0; idx < T; ++idx) {\n                        int task = obs[j][idx].task;\n                        int w = base[idx] + max(0, d[task][k] - x);\n                        obj += loss_interval(w, obs[j][idx].t);\n                    }\n\n                    // weak regularization\n                    obj += 0.02 * (x - init_skill[k]) * (x - init_skill[k]);\n\n                    int tie1 = abs(x - prev);\n                    int tie2 = abs(x - init_skill[k]);\n                    if (obj + 1e-9 < best_obj ||\n                        (abs(obj - best_obj) <= 1e-9 &&\n                         (tie1 < best_tie1 || (tie1 == best_tie1 && tie2 < best_tie2)))) {\n                        best_obj = obj;\n                        best_x = x;\n                        best_tie1 = tie1;\n                        best_tie2 = tie2;\n                    }\n                }\n\n                if (best_x != prev) changed = true;\n                s[k] = best_x;\n\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    curW[idx] = base[idx] + max(0, d[task][k] - best_x);\n                }\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto estimate_time = [&](int member, int task) -> double {\n        // Blend default estimate and learned estimate based on observation count.\n        double trust = (double)obs[member].size() / ((double)obs[member].size() + 5.0);\n        int learned_w = calc_w_with_skill(task, skill_hat[member]);\n        double p = (1.0 - trust) * default_w[task] + trust * learned_w;\n\n        // Slight uncertainty penalty early on\n        p += (1.0 - trust) * 0.10 * default_w[task];\n\n        return max(1.0, p);\n    };\n\n    auto get_ready_tasks = [&]() -> vector<int> {\n        vector<int> ready;\n        ready.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (task_status[i] == -1 && rem_pre[i] == 0) ready.push_back(i);\n        }\n        return ready;\n    };\n\n    auto calc_unlock_bonus = [&](int task) -> pair<int, long long> {\n        int cnt = 0;\n        long long child_bottom_sum = 0;\n        for (int ch : children[task]) {\n            if (task_status[ch] == -1 && rem_pre[ch] == 1) {\n                ++cnt;\n                child_bottom_sum += bottom[ch];\n            }\n        }\n        return {cnt, child_bottom_sum};\n    };\n\n    auto dynamic_priority = [&](int task) -> long long {\n        auto [cnt, child_sum] = calc_unlock_bonus(task);\n        return base_priority[task] + 400LL * cnt + child_sum * 8LL;\n    };\n\n    auto select_candidates = [&](const vector<int>& ready, int free_cnt) -> vector<int> {\n        int limit = max(60, free_cnt * 5);\n        if ((int)ready.size() <= limit) return ready;\n\n        vector<pair<long long,int>> by_pri;\n        vector<pair<int,int>> by_easy;\n        vector<pair<long long,int>> by_unlock;\n\n        by_pri.reserve(ready.size());\n        by_easy.reserve(ready.size());\n        by_unlock.reserve(ready.size());\n\n        for (int t : ready) {\n            auto [cnt, child_sum] = calc_unlock_bonus(t);\n            by_pri.push_back({dynamic_priority(t), t});\n            by_easy.push_back({default_t[t], t});\n            by_unlock.push_back({(long long)cnt * 1000000LL + child_sum, t});\n        }\n\n        sort(by_pri.begin(), by_pri.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n        sort(by_easy.begin(), by_easy.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first < b.first;\n            return a.second < b.second;\n        });\n        sort(by_unlock.begin(), by_unlock.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int take_pri = max(25, free_cnt * 3);\n        int take_easy = max(15, free_cnt * 2);\n        int take_unlock = max(15, free_cnt * 2);\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(limit + 10);\n\n        for (int i = 0; i < (int)by_pri.size() && (int)cand.size() < take_pri; ++i) {\n            int t = by_pri[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_easy.size() && i < take_easy; ++i) {\n            int t = by_easy[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_unlock.size() && i < take_unlock; ++i) {\n            int t = by_unlock[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (auto &p : by_pri) {\n            if ((int)cand.size() >= limit) break;\n            int t = p.second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        return cand;\n    };\n\n    auto decide_assignments = [&]() -> vector<pair<int,int>> {\n        vector<int> free_members;\n        for (int j = 0; j < M; ++j) {\n            if (current_task[j] == -1) free_members.push_back(j);\n        }\n\n        vector<int> ready = get_ready_tasks();\n        if (free_members.empty() || ready.empty()) return {};\n\n        vector<int> cand = select_candidates(ready, (int)free_members.size());\n\n        int F = (int)free_members.size();\n        int C = (int)cand.size();\n\n        vector<long long> pri(C);\n        for (int ci = 0; ci < C; ++ci) pri[ci] = dynamic_priority(cand[ci]);\n\n        vector<vector<double>> pred(F, vector<double>(C));\n        vector<double> best_t(C, 1e100);\n\n        for (int fi = 0; fi < F; ++fi) {\n            int mem = free_members[fi];\n            for (int ci = 0; ci < C; ++ci) {\n                pred[fi][ci] = estimate_time(mem, cand[ci]);\n                best_t[ci] = min(best_t[ci], pred[fi][ci]);\n            }\n        }\n\n        // Greedy matching\n        // score = task value - time penalty - \"not the best member for this task\" penalty\n        const long long TIME_PENALTY = 850;\n        const long long GAP_PENALTY = 250;\n\n        vector<char> used_f(F, 0), used_c(C, 0);\n        vector<pair<int,int>> ret;\n        ret.reserve(min(F, C));\n\n        for (int step = 0; step < min(F, C); ++step) {\n            long long best_score = LLONG_MIN;\n            int best_f = -1, best_c = -1;\n\n            for (int fi = 0; fi < F; ++fi) if (!used_f[fi]) {\n                for (int ci = 0; ci < C; ++ci) if (!used_c[ci]) {\n                    double et = pred[fi][ci];\n                    double gap = et - best_t[ci];\n                    long long score = pri[ci]\n                        - (long long)llround(et * TIME_PENALTY)\n                        - (long long)llround(gap * GAP_PENALTY);\n\n                    if (score > best_score) {\n                        best_score = score;\n                        best_f = fi;\n                        best_c = ci;\n                    }\n                }\n            }\n\n            if (best_f == -1) break;\n            used_f[best_f] = 1;\n            used_c[best_c] = 1;\n            ret.emplace_back(free_members[best_f], cand[best_c]);\n        }\n\n        return ret;\n    };\n\n    // ----------------------------\n    // Interactive loop\n    // ----------------------------\n    int day = 0;\n    while (true) {\n        ++day;\n\n        vector<pair<int,int>> assigns = decide_assignments();\n\n        // Update local state before reading completions\n        for (auto [mem, task] : assigns) {\n            task_status[task] = 0;\n            current_task[mem] = task;\n            start_day[mem] = day;\n        }\n\n        // Output today's assignments\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) {\n            cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        }\n        cout << '\\n' << flush;\n\n        int nfin;\n        cin >> nfin;\n        if (!cin) return 0;\n        if (nfin == -1) return 0;\n\n        vector<int> finished(nfin);\n        for (int i = 0; i < nfin; ++i) {\n            cin >> finished[i];\n            --finished[i];\n        }\n\n        // Process completions\n        for (int mem : finished) {\n            int task = current_task[mem];\n            if (task == -1) continue; // safety\n\n            int duration = day - start_day[mem] + 1;\n            obs[mem].push_back({task, duration});\n\n            task_status[task] = 1;\n            current_task[mem] = -1;\n            start_day[mem] = -1;\n\n            for (int ch : children[task]) {\n                --rem_pre[ch];\n            }\n\n            optimize_member(mem);\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 1000;\nstatic constexpr int TOT = 2001; // 0: office, 1..1000 pickup, 1001..2000 delivery\nstatic constexpr double TL = 1.90;\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 XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Insertion {\n    int delta;\n    int g1, g2;\n};\n\nstruct SingleInsertion {\n    int delta;\n    int g;\n};\n\nstruct State {\n    vector<int> seq;\n    vector<char> selected;\n    int cost = 0;\n};\n\nint X[TOT], Y[TOT];\nvector<int> DM;\nint baseScore[N + 1];\nvector<int> sorted_ids;\n\ninline int dist_node(int a, int b) {\n    return DM[a * TOT + b];\n}\ninline int pickup_node(int id) { return id; }\ninline int delivery_node(int id) { return N + id; }\n\nint route_cost(const vector<int>& seq) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)seq.size(); i++) s += dist_node(seq[i], seq[i + 1]);\n    return s;\n}\n\nvector<int> get_selected_ids(const vector<char>& selected) {\n    vector<int> ids;\n    ids.reserve(50);\n    for (int id = 1; id <= N; id++) if (selected[id]) ids.push_back(id);\n    return ids;\n}\n\nInsertion find_best_insertion(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    const int m = (int)seq.size();\n\n    Insertion best{INT_MAX, -1, -1};\n\n    for (int g1 = 0; g1 < m - 1; g1++) {\n        int a = seq[g1], b = seq[g1 + 1];\n        int dab = dist_node(a, b);\n\n        // same gap: a-u-v-b\n        int delta_same = dist_node(a, u) + dist_node(u, v) + dist_node(v, b) - dab;\n        if (delta_same < best.delta) best = {delta_same, g1, g1};\n\n        // different gaps\n        int delta_pick = dist_node(a, u) + dist_node(u, b) - dab;\n        for (int g2 = g1 + 1; g2 < m - 1; g2++) {\n            int c = seq[g2], d = seq[g2 + 1];\n            int delta = delta_pick + dist_node(c, v) + dist_node(v, d) - dist_node(c, d);\n            if (delta < best.delta) best = {delta, g1, g2};\n        }\n    }\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& seq, int id, const Insertion& ins) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() + 2);\n\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == ins.g1) {\n            res.push_back(u);\n            if (ins.g2 == ins.g1) res.push_back(v);\n        }\n        if (i == ins.g2 && ins.g2 > ins.g1) {\n            res.push_back(v);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() - 2);\n    for (int x : seq) {\n        if (x != u && x != v) res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> remove_orders(const vector<int>& seq, const vector<int>& rem_ids) {\n    vector<char> bad(N + 1, 0);\n    for (int id : rem_ids) bad[id] = 1;\n    vector<int> res;\n    res.reserve(seq.size() - 2 * (int)rem_ids.size());\n    for (int x : seq) {\n        if (x == 0) {\n            res.push_back(x);\n        } else {\n            int id = (x <= N ? x : x - N);\n            if (!bad[id]) res.push_back(x);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_node_once(const vector<int>& seq, int node) {\n    vector<int> res;\n    res.reserve(seq.size() - 1);\n    bool skipped = false;\n    for (int x : seq) {\n        if (!skipped && x == node) {\n            skipped = true;\n            continue;\n        }\n        res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> insert_single_node(const vector<int>& seq, int node, int g) {\n    vector<int> res;\n    res.reserve(seq.size() + 1);\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == g) res.push_back(node);\n    }\n    return res;\n}\n\nSingleInsertion find_best_single_insertion(const vector<int>& seq, int node, int gl, int gr) {\n    int m = (int)seq.size();\n    gl = max(gl, 0);\n    gr = min(gr, m - 2);\n\n    SingleInsertion best{INT_MAX, -1};\n    for (int g = gl; g <= gr; g++) {\n        int a = seq[g], b = seq[g + 1];\n        int delta = dist_node(a, node) + dist_node(node, b) - dist_node(a, b);\n        if (delta < best.delta) best = {delta, g};\n    }\n    return best;\n}\n\nint pick_rcl_index(int sz, XorShift64& rng) {\n    if (sz <= 1) return 0;\n    int r = rng.next_int(0, 99);\n    if (sz == 2) return (r < 72 ? 0 : 1);\n    if (sz == 3) return (r < 55 ? 0 : (r < 85 ? 1 : 2));\n    if (sz == 4) return (r < 45 ? 0 : (r < 73 ? 1 : (r < 90 ? 2 : 3)));\n    if (sz == 5) return (r < 42 ? 0 : (r < 68 ? 1 : (r < 84 ? 2 : (r < 94 ? 3 : 4))));\n    return (r < 40 ? 0 : (r < 64 ? 1 : (r < 79 ? 2 : (r < 89 ? 3 : (r < 96 ? 4 : 5)))));\n}\n\nstruct Cand {\n    int delta;\n    int id;\n    Insertion ins;\n};\n\nvoid push_top_k(vector<Cand>& top, const Cand& c, int topK) {\n    if ((int)top.size() < topK) {\n        top.push_back(c);\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            return baseScore[a.id] < baseScore[b.id];\n        });\n    } else {\n        const auto& w = top.back();\n        if (c.delta < w.delta || (c.delta == w.delta && baseScore[c.id] < baseScore[w.id])) {\n            top.back() = c;\n            sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                if (a.delta != b.delta) return a.delta < b.delta;\n                return baseScore[a.id] < baseScore[b.id];\n            });\n        }\n    }\n}\n\nvector<Cand> collect_top_insertions(\n    const vector<int>& seq,\n    const vector<char>& selected,\n    int limit_ids,\n    int topK,\n    const Timer* timer = nullptr,\n    double end_time = 1e100\n) {\n    vector<Cand> top;\n    top.reserve(topK);\n\n    int lim = min(limit_ids, (int)sorted_ids.size());\n    for (int i = 0; i < lim; i++) {\n        if (timer && timer->elapsed() >= end_time) break;\n        int id = sorted_ids[i];\n        if (selected[id]) continue;\n        Insertion ins = find_best_insertion(seq, id);\n        push_top_k(top, Cand{ins.delta, id, ins}, topK);\n    }\n\n    if (top.empty()) {\n        for (int id = 1; id <= N; id++) {\n            if (selected[id]) continue;\n            Insertion ins = find_best_insertion(seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n    }\n\n    return top;\n}\n\nState construct_solution(int pool_limit, bool randomized, XorShift64& rng, const Timer& timer, double end_time) {\n    State st;\n    st.seq = {0, 0};\n    st.selected.assign(N + 1, 0);\n    st.cost = 0;\n\n    int cnt = 0;\n    int topK = randomized ? 6 : 1;\n\n    while (cnt < 50) {\n        if (timer.elapsed() >= end_time) break;\n        auto top = collect_top_insertions(st.seq, st.selected, pool_limit, topK, &timer, end_time);\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    while (cnt < 50) {\n        auto top = collect_top_insertions(st.seq, st.selected, N, 1);\n        auto chosen = top[0];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    return st;\n}\n\nState rebuild_route_for_selected(const vector<char>& selected, bool randomized, XorShift64& rng) {\n    vector<int> ids = get_selected_ids(selected);\n\n    State st;\n    st.seq = {0, 0};\n    st.selected = selected;\n    st.cost = 0;\n\n    vector<char> used(N + 1, 0);\n    int topK = randomized ? 5 : 1;\n\n    for (int step = 0; step < 50; step++) {\n        vector<Cand> top;\n        top.reserve(topK);\n        for (int id : ids) {\n            if (used[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.cost += chosen.delta;\n        used[chosen.id] = 1;\n    }\n    return st;\n}\n\nbool improve_event_relocate(State& st, const Timer& timer, double end_time, int max_passes = 50) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        vector<int> pos(TOT, -1);\n        for (int i = 0; i < (int)st.seq.size(); i++) pos[st.seq[i]] = i;\n\n        int best_new_cost = st.cost;\n        int best_node = -1;\n        int best_gap = -1;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            int u = pickup_node(id);\n            int v = delivery_node(id);\n            int pu = pos[u];\n            int pv = pos[v];\n\n            // Move pickup only\n            {\n                int prev = st.seq[pu - 1];\n                int next = st.seq[pu + 1];\n                int cost_removed = st.cost - (dist_node(prev, u) + dist_node(u, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, u);\n\n                int pdr = pv - 1;\n                auto ins = find_best_single_insertion(seq_removed, u, 0, pdr - 1);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = u;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n\n            // Move delivery only\n            {\n                int prev = st.seq[pv - 1];\n                int next = st.seq[pv + 1];\n                int cost_removed = st.cost - (dist_node(prev, v) + dist_node(v, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, v);\n\n                int ppr = pu;\n                auto ins = find_best_single_insertion(seq_removed, v, ppr, (int)seq_removed.size() - 2);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = v;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n        }\n\n        if (best_node == -1) break;\n        vector<int> seq_removed = remove_node_once(st.seq, best_node);\n        st.seq = insert_single_node(seq_removed, best_node, best_gap);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\nbool improve_pair_relocate(State& st, const Timer& timer, double end_time, int max_passes = 100) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_new_cost = st.cost;\n        int best_id = -1;\n        Insertion best_ins;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int cost_removed = route_cost(seq_removed);\n            Insertion ins = find_best_insertion(seq_removed, id);\n            int new_cost = cost_removed + ins.delta;\n\n            if (new_cost < best_new_cost) {\n                best_new_cost = new_cost;\n                best_id = id;\n                best_ins = ins;\n            }\n        }\n\n        if (best_id == -1) break;\n        vector<int> seq_removed = remove_order(st.seq, best_id);\n        st.seq = apply_insertion(seq_removed, best_id, best_ins);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\n// Valid 2-opt with precedence:\n// Reversing [l, r] is valid iff no order has both endpoints inside [l, r].\nbool improve_two_opt(State& st, const Timer& timer, double end_time, int max_passes = 20) {\n    bool any = false;\n    int m = (int)st.seq.size();\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_delta = 0;\n        int best_l = -1, best_r = -1;\n\n        vector<int> cnt(N + 1, 0);\n\n        for (int l = 1; l <= m - 3; l++) {\n            if (timer.elapsed() >= end_time) break;\n            fill(cnt.begin(), cnt.end(), 0);\n\n            for (int r = l; r <= m - 2; r++) {\n                int node = st.seq[r];\n                if (node == 0) break;\n                int id = (node <= N ? node : node - N);\n                cnt[id]++;\n                if (cnt[id] == 2) break; // larger r also invalid\n\n                int delta =\n                    dist_node(st.seq[l - 1], st.seq[r]) +\n                    dist_node(st.seq[l], st.seq[r + 1]) -\n                    dist_node(st.seq[l - 1], st.seq[l]) -\n                    dist_node(st.seq[r], st.seq[r + 1]);\n\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_l = l;\n                    best_r = r;\n                }\n            }\n        }\n\n        if (best_l == -1) break;\n        reverse(st.seq.begin() + best_l, st.seq.begin() + best_r + 1);\n        st.cost += best_delta;\n        any = true;\n    }\n\n    return any;\n}\n\nvoid optimize_route(State& st, const Timer& timer, double end_time) {\n    while (timer.elapsed() < end_time) {\n        int old_cost = st.cost;\n\n        double t0 = min(end_time, timer.elapsed() + 0.020);\n        improve_two_opt(st, timer, t0, 3);\n\n        double t1 = min(end_time, timer.elapsed() + 0.020);\n        improve_event_relocate(st, timer, t1, 3);\n\n        double t2 = min(end_time, timer.elapsed() + 0.020);\n        improve_pair_relocate(st, timer, t2, 2);\n\n        if (st.cost >= old_cost) break;\n    }\n}\n\nvoid improve_swap(State& st, const Timer& timer, double end_time) {\n    const int TOP_REMOVE = 12;\n    const int TOP_ADD = 120;\n\n    while (timer.elapsed() < end_time) {\n        struct RemCand {\n            int gain;\n            int id;\n        };\n        vector<RemCand> rems;\n        rems.reserve(50);\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int removed_cost = route_cost(seq_removed);\n            int gain = st.cost - removed_cost;\n            rems.push_back({gain, id});\n        }\n\n        sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.id < b.id;\n        });\n        if ((int)rems.size() > TOP_REMOVE) rems.resize(TOP_REMOVE);\n\n        vector<Cand> adds;\n        adds.reserve(TOP_ADD);\n        for (int id = 1; id <= N; id++) {\n            if (timer.elapsed() >= end_time) break;\n            if (st.selected[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(adds, Cand{ins.delta, id, ins}, TOP_ADD);\n        }\n\n        int best_new_cost = st.cost;\n        int best_remove = -1, best_add = -1;\n        Insertion best_ins;\n\n        for (const auto& rc : rems) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> seq_removed = remove_order(st.seq, rc.id);\n            int cost_removed = route_cost(seq_removed);\n\n            for (const auto& ac : adds) {\n                Insertion ins = find_best_insertion(seq_removed, ac.id);\n                int new_cost = cost_removed + ins.delta;\n                if (new_cost < best_new_cost) {\n                    best_new_cost = new_cost;\n                    best_remove = rc.id;\n                    best_add = ac.id;\n                    best_ins = ins;\n                }\n            }\n        }\n\n        if (best_remove == -1) break;\n\n        st.selected[best_remove] = 0;\n        st.selected[best_add] = 1;\n        vector<int> seq_removed = remove_order(st.seq, best_remove);\n        st.seq = apply_insertion(seq_removed, best_add, best_ins);\n        st.cost = best_new_cost;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(st, timer, sub_end);\n    }\n}\n\nbool destroy_and_repair_once(State& st, const Timer& timer, double end_time, XorShift64& rng) {\n    if (timer.elapsed() >= end_time) return false;\n\n    auto selected_ids = get_selected_ids(st.selected);\n\n    struct RemCand {\n        int gain;\n        int id;\n    };\n    vector<RemCand> rems;\n    rems.reserve(50);\n    for (int id : selected_ids) {\n        vector<int> seq_removed = remove_order(st.seq, id);\n        int removed_cost = route_cost(seq_removed);\n        int gain = st.cost - removed_cost;\n        rems.push_back({gain, id});\n    }\n    sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        return a.id < b.id;\n    });\n\n    int elite_rem = min(12, (int)rems.size());\n\n    for (int trial = 0; trial < 12 && timer.elapsed() < end_time; trial++) {\n        int k = (rng.next_int(0, 99) < 70 ? 2 : 3);\n\n        vector<int> remset;\n        remset.reserve(k);\n        while ((int)remset.size() < k) {\n            int id;\n            if (rng.next_int(0, 99) < 80) {\n                id = rems[rng.next_int(0, elite_rem - 1)].id;\n            } else {\n                id = selected_ids[rng.next_int(0, (int)selected_ids.size() - 1)];\n            }\n            bool dup = false;\n            for (int x : remset) if (x == id) dup = true;\n            if (!dup) remset.push_back(id);\n        }\n\n        State tmp;\n        tmp.selected = st.selected;\n        for (int id : remset) tmp.selected[id] = 0;\n        tmp.seq = remove_orders(st.seq, remset);\n        tmp.cost = route_cost(tmp.seq);\n\n        for (int rep = 0; rep < k; rep++) {\n            if (timer.elapsed() >= end_time) break;\n            auto top = collect_top_insertions(tmp.seq, tmp.selected, 800, 6, &timer, end_time);\n            int idx = pick_rcl_index((int)top.size(), rng);\n            auto chosen = top[idx];\n            tmp.seq = apply_insertion(tmp.seq, chosen.id, chosen.ins);\n            tmp.selected[chosen.id] = 1;\n            tmp.cost += chosen.delta;\n        }\n\n        if ((int)get_selected_ids(tmp.selected).size() != 50) continue;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(tmp, timer, sub_end);\n\n        if (tmp.cost < st.cost) {\n            st = move(tmp);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    X[0] = 400;\n    Y[0] = 400;\n\n    long long seed = 123456789;\n\n    for (int i = 1; i <= N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        X[i] = a;\n        Y[i] = b;\n        X[N + i] = c;\n        Y[N + i] = d;\n\n        int d0p = abs(400 - a) + abs(400 - b);\n        int dpd = abs(a - c) + abs(b - d);\n        int dd0 = abs(c - 400) + abs(d - 400);\n        int center_sum = d0p + dd0;\n        baseScore[i] = 3 * (d0p + dpd + dd0) + center_sum;\n\n        seed = seed * 1000003 + a * 911 + b * 3571 + c * 1021 + d;\n    }\n\n    DM.assign(TOT * TOT, 0);\n    for (int i = 0; i < TOT; i++) {\n        for (int j = 0; j < TOT; j++) {\n            DM[i * TOT + j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n        }\n    }\n\n    sorted_ids.resize(N);\n    iota(sorted_ids.begin(), sorted_ids.end(), 1);\n    sort(sorted_ids.begin(), sorted_ids.end(), [](int i, int j) {\n        if (baseScore[i] != baseScore[j]) return baseScore[i] < baseScore[j];\n        return i < j;\n    });\n\n    Timer timer;\n    XorShift64 rng((uint64_t)seed);\n\n    State best;\n    bool has_best = false;\n\n    // Multi-start construction\n    vector<int> pool_limits = {150, 220, 320, 450, 650, 1000};\n    int attempt = 0;\n    while (timer.elapsed() < 0.52) {\n        int pool = pool_limits[attempt % (int)pool_limits.size()];\n        bool randomized = (attempt > 0);\n        State st = construct_solution(pool, randomized, rng, timer, 0.56);\n\n        double sub_end = min(0.72, TL);\n        optimize_route(st, timer, sub_end);\n\n        if (!has_best || st.cost < best.cost) {\n            best = move(st);\n            has_best = true;\n        }\n        attempt++;\n    }\n\n    if (!has_best) {\n        best = construct_solution(1000, false, rng, timer, TL);\n    }\n\n    optimize_route(best, timer, 1.02);\n    improve_swap(best, timer, 1.32);\n    optimize_route(best, timer, 1.52);\n\n    while (timer.elapsed() < 1.72) {\n        if (!destroy_and_repair_once(best, timer, 1.76, rng)) break;\n    }\n\n    while (timer.elapsed() < 1.84) {\n        State cand = rebuild_route_for_selected(best.selected, true, rng);\n        double sub_end = min(1.88, TL);\n        optimize_route(cand, timer, sub_end);\n        if (cand.cost < best.cost) best = move(cand);\n    }\n\n    optimize_route(best, timer, TL - 0.01);\n\n    auto ids = get_selected_ids(best.selected);\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.seq.size();\n    for (int node : best.seq) {\n        cout << ' ' << X[node] << ' ' << Y[node];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int S = 32;          // even, antithetic sampling\nstatic constexpr int INF = 1e9;\n\nstruct Edge {\n    int u, v;\n    int d;\n};\n\ntemplate <int MAXN>\nstruct UnionFind {\n    int p[MAXN], sz[MAXN];\n\n    inline void init(int n) {\n        for (int i = 0; i < n; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\n\n    inline int leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline int leader_const(int x) const {\n        while (p[x] != x) x = p[x];\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    inline bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 0x123456789abcdefULL) : 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(uint32_t mod) {\n        return (uint32_t)(next_u64() % mod);\n    }\n};\n\n// In one sampled future world:\n// - return INF if the remaining graph cannot connect current components.\n// - otherwise return the exact deterministic \"replacement threshold\" of the current edge,\n//   i.e. reject_cost - adopt_completion_cost for that world.\nstatic inline int estimate_threshold(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int cu,\n    int cv,\n    const vector<int>& order,\n    const vector<int>& weight,\n    const vector<Edge>& edges\n) {\n    if (K == 1) return 0;\n\n    UnionFind<N> uf;\n    uf.init(K);\n\n    int need = K - 1;\n    int threshold = -1;\n\n    for (int idx : order) {\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (uf.merge(a, b)) {\n            if (threshold < 0 && uf.same(cu, cv)) {\n                threshold = weight[idx];\n            }\n            if (--need == 0) break;\n        }\n    }\n\n    if (need > 0) return INF;\n    return threshold; // should be set if graph became connected\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<pair<int, int>> pos(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> pos[i].first >> pos[i].second;\n    }\n\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = pos[u].first - pos[v].first;\n        long long dy = pos[u].second - pos[v].second;\n        int d = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Pre-sample future worlds using antithetic sampling.\n    vector<vector<int>> weights(S, vector<int>(M));\n    SplitMix64 rng(0x3141592653589793ULL);\n\n    for (int s = 0; s < S; s += 2) {\n        for (int i = 0; i < M; ++i) {\n            int d = edges[i].d;\n            int t = (int)rng.next_u32((uint32_t)(2 * d + 1)); // in [0, 2d]\n            weights[s][i] = d + t;\n            weights[s + 1][i] = 3 * d - t;\n        }\n    }\n\n    vector<vector<int>> orders(S, vector<int>(M));\n    for (int s = 0; s < S; ++s) {\n        iota(orders[s].begin(), orders[s].end(), 0);\n        stable_sort(orders[s].begin(), orders[s].end(), [&](int a, int b) {\n            if (weights[s][a] != weights[s][b]) return weights[s][a] < weights[s][b];\n            return a < b;\n        });\n    }\n\n    UnionFind<N> accepted;\n    accepted.init(N);\n\n    int cid[N];\n    int K = N;\n    bool comp_dirty = true;\n\n    auto rebuild_components = [&]() {\n        int mp[N];\n        for (int i = 0; i < N; ++i) mp[i] = -1;\n        K = 0;\n        for (int v = 0; v < N; ++v) {\n            int r = accepted.leader_const(v);\n            if (mp[r] == -1) mp[r] = K++;\n            cid[v] = mp[r];\n        }\n        comp_dirty = false;\n    };\n\n    for (int i = 0; i < M; ++i) {\n        int l;\n        cin >> l;\n\n        int u = edges[i].u;\n        int v = edges[i].v;\n        int ans = 0;\n\n        if (!accepted.same(u, v)) {\n            if (comp_dirty) rebuild_components();\n\n            int cu = cid[u];\n            int cv = cid[v];\n\n            long long sum_thr = 0;\n            bool must_adopt = false;\n\n            for (int s = 0; s < S; ++s) {\n                int thr = estimate_threshold(i + 1, K, cid, cu, cv, orders[s], weights[s], edges);\n                if (thr >= INF) {\n                    must_adopt = true;\n                    break;\n                }\n                sum_thr += thr;\n            }\n\n            if (must_adopt) {\n                ans = 1;\n            } else {\n                double mean_thr = (double)sum_thr / S;\n                if ((double)l <= mean_thr) ans = 1;\n            }\n        }\n\n        if (ans) {\n            accepted.merge(u, v);\n            comp_dirty = true;\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n    bool operator==(const Pos& o) const { return x == o.x && y == o.y; }\n    bool operator!=(const Pos& o) const { return !(*this == o); }\n};\n\nstatic constexpr int B = 30;\nstatic constexpr int T = 300;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nvector<Pos> pets, humans;\nvector<int> petType;\nbool wallg[31][31];\n\nint chosenCorner = 0;\nint Hrect = 8, Wrect = 8;\n// 0: keep bottom door (H+1, W) open\n// 1: keep right  door (H, W+1) open\nint keepDoor = 0;\n\nvector<Pos> parkTarget;\n\nbool inside(int x, int y) {\n    return 1 <= x && x <= B && 1 <= y && y <= B;\n}\n\nPos addDir(Pos p, char d) {\n    if (d == 'U' || d == 'u') --p.x;\n    else if (d == 'D' || d == 'd') ++p.x;\n    else if (d == 'L' || d == 'l') --p.y;\n    else if (d == 'R' || d == 'r') ++p.y;\n    return p;\n}\n\nPos transformPos(Pos p, int corner) {\n    if (corner == 0) return p;                    // TL\n    if (corner == 1) return {p.x, B + 1 - p.y};  // TR -> TL\n    if (corner == 2) return {B + 1 - p.x, p.y};  // BL -> TL\n    return {B + 1 - p.x, B + 1 - p.y};           // BR -> TL\n}\n\nchar mapDirByCorner(char c, int corner) {\n    bool low = ('a' <= c && c <= 'z');\n    char d = (char)toupper(c);\n    if (corner == 1 || corner == 3) {\n        if (d == 'L') d = 'R';\n        else if (d == 'R') d = 'L';\n    }\n    if (corner == 2 || corner == 3) {\n        if (d == 'U') d = 'D';\n        else if (d == 'D') d = 'U';\n    }\n    if (low) d = (char)tolower(d);\n    return d;\n}\n\nint manhattan(Pos a, Pos b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<Pos> transformedVec(const vector<Pos>& src, int corner) {\n    vector<Pos> res = src;\n    for (auto& p : res) p = transformPos(p, corner);\n    return res;\n}\n\nbool canBuildCell(int tx, int ty, const vector<Pos>& hs, const vector<Pos>& ps) {\n    if (!inside(tx, ty)) return false;\n    if (wallg[tx][ty]) return false;\n    for (auto& h : hs) {\n        if (h.x == tx && h.y == ty) return false;\n    }\n    for (auto& p : ps) {\n        if (p.x == tx && p.y == ty) return false;\n        if (abs(p.x - tx) + abs(p.y - ty) == 1) return false;\n    }\n    return true;\n}\n\nchar bfsNextStep(Pos s, Pos t) {\n    if (s == t) return '.';\n    if (!inside(t.x, t.y) || wallg[t.x][t.y]) return '.';\n\n    static int dist[31][31];\n    for (int i = 1; i <= B; ++i) for (int j = 1; j <= B; ++j) dist[i][j] = -1;\n\n    queue<Pos> q;\n    q.push(t);\n    dist[t.x][t.y] = 0;\n\n    const char dirs[4] = {'U', 'D', 'L', 'R'};\n    while (!q.empty()) {\n        Pos cur = q.front(); q.pop();\n        for (char d : dirs) {\n            Pos nx = addDir(cur, d);\n            if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n            if (dist[nx.x][nx.y] != -1) continue;\n            dist[nx.x][nx.y] = dist[cur.x][cur.y] + 1;\n            q.push(nx);\n        }\n    }\n\n    int best = INF;\n    char ans = '.';\n    const char order[4] = {'U', 'L', 'R', 'D'};\n    for (char d : order) {\n        Pos nx = addDir(s, d);\n        if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n        if (dist[nx.x][nx.y] == -1) continue;\n        if (dist[nx.x][nx.y] < best) {\n            best = dist[nx.x][nx.y];\n            ans = d;\n        }\n    }\n    return ans;\n}\n\nbool allHumansInside(const vector<Pos>& hs) {\n    for (auto& h : hs) {\n        if (h.x > Hrect || h.y > Wrect) return false;\n    }\n    return true;\n}\n\nint countPetsInside(const vector<Pos>& ps) {\n    int c = 0;\n    for (auto& p : ps) if (p.x <= Hrect && p.y <= Wrect) ++c;\n    return c;\n}\n\nstruct Task {\n    Pos pos;   // human stands here\n    Pos wall;  // build this wall\n    char act;  // build action from pos\n};\n\nPos finalDoorCell() {\n    if (keepDoor == 0) return {Hrect + 1, Wrect};\n    return {Hrect, Wrect + 1};\n}\n\nchar finalDoorBuildAct() {\n    if (keepDoor == 0) return 'd';\n    return 'r';\n}\n\nvector<Task> getBuildTasks() {\n    vector<Task> tasks;\n    if (keepDoor == 0) {\n        // keep (H+1, W) open\n        for (int y = 1; y <= Wrect - 1; ++y) {\n            if (!wallg[Hrect + 1][y]) tasks.push_back({{Hrect, y}, {Hrect + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= Hrect; ++x) {\n            if (!wallg[x][Wrect + 1]) tasks.push_back({{x, Wrect}, {x, Wrect + 1}, 'r'});\n        }\n    } else {\n        // keep (H, W+1) open\n        for (int y = 1; y <= Wrect; ++y) {\n            if (!wallg[Hrect + 1][y]) tasks.push_back({{Hrect, y}, {Hrect + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= Hrect - 1; ++x) {\n            if (!wallg[x][Wrect + 1]) tasks.push_back({{x, Wrect}, {x, Wrect + 1}, 'r'});\n        }\n    }\n    return tasks;\n}\n\nbool allWallsExceptDoorBuilt() {\n    if (keepDoor == 0) {\n        for (int y = 1; y <= Wrect - 1; ++y) if (!wallg[Hrect + 1][y]) return false;\n        for (int x = 1; x <= Hrect; ++x) if (!wallg[x][Wrect + 1]) return false;\n    } else {\n        for (int y = 1; y <= Wrect; ++y) if (!wallg[Hrect + 1][y]) return false;\n        for (int x = 1; x <= Hrect - 1; ++x) if (!wallg[x][Wrect + 1]) return false;\n    }\n    return true;\n}\n\nbool fullyClosed() {\n    Pos d = finalDoorCell();\n    return allWallsExceptDoorBuilt() && wallg[d.x][d.y];\n}\n\nint nearestHumanTo(Pos target, const vector<Pos>& hs) {\n    int id = 0, bd = INF;\n    for (int i = 0; i < (int)hs.size(); ++i) {\n        int d = manhattan(hs[i], target);\n        if (d < bd) {\n            bd = d;\n            id = i;\n        }\n    }\n    return id;\n}\n\ndouble doorPressure(const vector<Pos>& ps, Pos doorCell) {\n    double s = 0.0;\n    for (auto& p : ps) {\n        int d = manhattan(p, doorCell);\n        if (d <= 8) s += (9 - d);\n    }\n    return s;\n}\n\nvoid chooseStrategy(const vector<Pos>& initPetsActual, const vector<Pos>& initHumansActual) {\n    double bestValue = -1e100;\n    int bestCorner = 0, bestH = 8, bestW = 8, bestKeep = 0;\n\n    for (int corner = 0; corner < 4; ++corner) {\n        auto tp = transformedVec(initPetsActual, corner);\n        auto th = transformedVec(initHumansActual, corner);\n\n        int occ[31][31] = {};\n        for (auto& p : tp) occ[p.x][p.y]++;\n\n        int pref[31][31] = {};\n        for (int i = 1; i <= B; ++i) {\n            for (int j = 1; j <= B; ++j) {\n                pref[i][j] = occ[i][j] + pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1];\n            }\n        }\n\n        for (int H = 4; H <= 18; ++H) {\n            for (int W = 4; W <= 18; ++W) {\n                int petCnt = pref[H][W];\n\n                int enterSum = 0, enterMax = 0;\n                for (auto& h : th) {\n                    int d = max(0, h.x - H) + max(0, h.y - W);\n                    enterSum += d;\n                    enterMax = max(enterMax, d);\n                }\n\n                for (int kd = 0; kd < 2; ++kd) {\n                    Pos fd = (kd == 0 ? Pos{H + 1, W} : Pos{H, W + 1});\n                    double pDoor = doorPressure(tp, fd);\n\n                    int buildCells = H + W - 1; // final one-cell gap kept open\n                    double value =\n                        1.0 * H * W * pow(0.43, petCnt)\n                        - 0.50 * enterSum\n                        - 0.22 * enterMax\n                        - 0.22 * buildCells\n                        - 0.70 * pDoor;\n\n                    if (petCnt == 0) value += 26.0;\n                    else if (petCnt == 1) value += 5.0;\n                    else if (petCnt == 2) value -= 1.0;\n                    else value -= 3.0 * (petCnt - 2);\n\n                    if (value > bestValue) {\n                        bestValue = value;\n                        bestCorner = corner;\n                        bestH = H;\n                        bestW = W;\n                        bestKeep = kd;\n                    }\n                }\n            }\n        }\n    }\n\n    chosenCorner = bestCorner;\n    Hrect = bestH;\n    Wrect = bestW;\n    keepDoor = bestKeep;\n\n    pets = transformedVec(initPetsActual, chosenCorner);\n    humans = transformedVec(initHumansActual, chosenCorner);\n\n    memset(wallg, 0, sizeof(wallg));\n\n    // parking positions inside rectangle\n    vector<Pos> spots;\n    for (int sum = 2; sum <= Hrect + Wrect; ++sum) {\n        for (int x = 1; x <= Hrect; ++x) {\n            int y = sum - x;\n            if (1 <= y && y <= Wrect) {\n                if (x == Hrect && y == Wrect) continue;\n                spots.push_back({x, y});\n            }\n        }\n    }\n    if (spots.empty()) spots.push_back({1, 1});\n\n    parkTarget.assign(M, {1, 1});\n    vector<int> used(spots.size(), 0);\n    for (int i = 0; i < M; ++i) {\n        int best = -1, bestd = INF;\n        for (int k = 0; k < (int)spots.size(); ++k) if (!used[k]) {\n            int d = manhattan(humans[i], spots[k]);\n            if (d < bestd) {\n                bestd = d;\n                best = k;\n            }\n        }\n        if (best == -1) best = 0;\n        used[best] = 1;\n        parkTarget[i] = spots[best];\n    }\n}\n\nbool shouldCloseFinalDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 205 && petsInside <= 1) return true;\n    if (turn >= 255 && petsInside <= 2) return true;\n    if (turn >= 292 && petsInside <= 3) return true;\n    if (turn >= 297) return true;\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<Pos> initPetsActual(N);\n    petType.resize(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> initPetsActual[i].x >> initPetsActual[i].y >> petType[i];\n    }\n\n    cin >> M;\n    vector<Pos> initHumansActual(M);\n    for (int i = 0; i < M; ++i) cin >> initHumansActual[i].x >> initHumansActual[i].y;\n\n    chooseStrategy(initPetsActual, initHumansActual);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<Pos> hs0 = humans;\n        vector<Pos> ps0 = pets;\n        vector<char> act(M, '.');\n\n        if (!allWallsExceptDoorBuilt()) {\n            vector<Task> tasks = getBuildTasks();\n            Pos corner = {Hrect, Wrect};\n\n            int reserveCloser = -1;\n            int reserveThreshold = max(2, M / 3);\n            if ((int)tasks.size() <= reserveThreshold || turn >= 220) {\n                reserveCloser = nearestHumanTo(corner, hs0);\n            }\n\n            vector<int> assignedTask(M, -1);\n            vector<int> usedTask(tasks.size(), 0);\n            vector<int> usedHuman(M, 0);\n\n            if (reserveCloser != -1) {\n                usedHuman[reserveCloser] = 1;\n                act[reserveCloser] = bfsNextStep(hs0[reserveCloser], corner);\n            }\n\n            // Immediate build opportunities.\n            for (int i = 0; i < M; ++i) {\n                if (usedHuman[i]) continue;\n                for (int t = 0; t < (int)tasks.size(); ++t) {\n                    if (usedTask[t]) continue;\n                    if (hs0[i] == tasks[t].pos &&\n                        canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) {\n                        assignedTask[i] = t;\n                        usedTask[t] = 1;\n                        usedHuman[i] = 1;\n                        break;\n                    }\n                }\n            }\n\n            struct Cand {\n                int d, i, t;\n                bool operator<(const Cand& o) const {\n                    if (d != o.d) return d < o.d;\n                    if (i != o.i) return i < o.i;\n                    return t < o.t;\n                }\n            };\n            vector<Cand> cand;\n            for (int i = 0; i < M; ++i) if (!usedHuman[i]) {\n                for (int t = 0; t < (int)tasks.size(); ++t) if (!usedTask[t]) {\n                    int d = manhattan(hs0[i], tasks[t].pos);\n                    if (hs0[i] == tasks[t].pos &&\n                        !canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) d += 3;\n                    cand.push_back({d, i, t});\n                }\n            }\n            sort(cand.begin(), cand.end());\n            for (auto& c : cand) {\n                if (usedHuman[c.i] || usedTask[c.t]) continue;\n                usedHuman[c.i] = 1;\n                usedTask[c.t] = 1;\n                assignedTask[c.i] = c.t;\n            }\n\n            for (int i = 0; i < M; ++i) {\n                if (assignedTask[i] != -1) {\n                    auto& task = tasks[assignedTask[i]];\n                    if (hs0[i] == task.pos) {\n                        if (canBuildCell(task.wall.x, task.wall.y, hs0, ps0)) act[i] = task.act;\n                        else act[i] = '.';\n                    } else {\n                        act[i] = bfsNextStep(hs0[i], task.pos);\n                    }\n                } else if (i != reserveCloser) {\n                    act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                }\n            }\n        } else if (!fullyClosed()) {\n            Pos corner = {Hrect, Wrect};\n            Pos fdoor = finalDoorCell();\n            char fact = finalDoorBuildAct();\n            int closer = nearestHumanTo(corner, hs0);\n\n            for (int i = 0; i < M; ++i) {\n                if (i == closer) continue;\n                act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n            }\n\n            bool allIn = allHumansInside(hs0);\n            int petsInside = countPetsInside(ps0);\n            bool doClose = allIn && shouldCloseFinalDoor(turn, petsInside);\n\n            if (hs0[closer] != corner) {\n                act[closer] = bfsNextStep(hs0[closer], corner);\n            } else {\n                if (doClose && canBuildCell(fdoor.x, fdoor.y, hs0, ps0)) act[closer] = fact;\n                else act[closer] = '.';\n            }\n        } else {\n            for (int i = 0; i < M; ++i) act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n        }\n\n        // sanitize build actions\n        set<pair<int,int>> buildSet;\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!canBuildCell(t.x, t.y, hs0, ps0)) {\n                    act[i] = '.';\n                    continue;\n                }\n                if (buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                    continue;\n                }\n                buildSet.insert({t.x, t.y});\n            }\n        }\n\n        // sanitize move actions\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!inside(t.x, t.y) || wallg[t.x][t.y] || buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        string out(M, '.');\n        for (int i = 0; i < M; ++i) out[i] = mapDirByCorner(act[i], chosenCorner);\n        cout << out << '\\n';\n        cout.flush();\n\n        // update walls\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (canBuildCell(t.x, t.y, hs0, ps0)) wallg[t.x][t.y] = true;\n            }\n        }\n\n        // update humans\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (inside(t.x, t.y) && !wallg[t.x][t.y] && !buildSet.count({t.x, t.y})) {\n                    humans[i] = t;\n                }\n            }\n        }\n\n        // read pet moves\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                if (c == '.') continue;\n                char nc = mapDirByCorner(c, chosenCorner);\n                pets[i] = addDir(pets[i], nc);\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 = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr char DIRS[4] = {'U', 'D', 'L', 'R'};\n\nint si, sj, ti, tj;\ndouble P, Q;\nstring hwall[N];\nstring vwall[N - 1];\n\nint start_id, target_id;\nint nxtPos[V][4];\nint distToTarget[V];\n\ndouble adaptDP[MAXL + 2][V];\ndouble fwdDist[MAXL + 1][V];\n\ninline int id(int i, int j) { return i * N + j; }\ninline int r_of(int x) { return x / N; }\ninline int c_of(int x) { return x % N; }\n\ninline int dirIndex(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct State {\n    array<float, V> pr{};\n    array<char, MAXL> path{};\n    double score = 0.0;\n    double upper = 0.0;\n    double pri = 0.0;\n    int len = 0;\n};\n\nstring toString(const State& st) {\n    return string(st.path.begin(), st.path.begin() + st.len);\n}\n\nvoid buildTransitions() {\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int x = id(i, j);\n\n            // U\n            if (i == 0 || vwall[i - 1][j] == '1') nxtPos[x][0] = x;\n            else nxtPos[x][0] = id(i - 1, j);\n\n            // D\n            if (i == N - 1 || vwall[i][j] == '1') nxtPos[x][1] = x;\n            else nxtPos[x][1] = id(i + 1, j);\n\n            // L\n            if (j == 0 || hwall[i][j - 1] == '1') nxtPos[x][2] = x;\n            else nxtPos[x][2] = id(i, j - 1);\n\n            // R\n            if (j == N - 1 || hwall[i][j] == '1') nxtPos[x][3] = x;\n            else nxtPos[x][3] = id(i, j + 1);\n        }\n    }\n}\n\nvoid bfsTargetDist() {\n    fill(distToTarget, distToTarget + V, (int)1e9);\n    queue<int> q;\n    distToTarget[target_id] = 0;\n    q.push(target_id);\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        int d = distToTarget[x];\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (distToTarget[y] > d + 1) {\n                distToTarget[y] = d + 1;\n                q.push(y);\n            }\n        }\n    }\n}\n\n// Relaxation: from each exact cell, future actions may be chosen adaptively.\n// This is an upper bound for the real open-loop problem.\nvoid buildAdaptiveDP() {\n    for (int x = 0; x < V; x++) adaptDP[MAXL + 1][x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        for (int x = 0; x < V; x++) {\n            if (x == target_id) {\n                adaptDP[step][x] = 0.0;\n                continue;\n            }\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int y = nxtPos[x][a];\n                double val = P * adaptDP[step + 1][x];\n                if (y == target_id) val += Q * reward;\n                else val += Q * adaptDP[step + 1][y];\n                if (val > best) best = val;\n            }\n            adaptDP[step][x] = best;\n        }\n    }\n}\n\nState initialState() {\n    State st;\n    st.pr.fill(0.0f);\n    st.pr[start_id] = 1.0f;\n    st.score = 0.0;\n    st.len = 0;\n    st.upper = adaptDP[1][start_id];\n    st.pri = st.upper + 5.0;\n    return st;\n}\n\nState extendState(const State& st, int a, int step) {\n    State nx;\n    nx.pr.fill(0.0f);\n    nx.path = st.path;\n    nx.path[st.len] = DIRS[a];\n    nx.len = st.len + 1;\n    nx.score = st.score;\n\n    double reward = 401.0 - step;\n\n    for (int x = 0; x < V; x++) {\n        float q = st.pr[x];\n        if (q < 1e-8f) continue;\n\n        int y = nxtPos[x][a];\n        if (y == target_id) {\n            float stay = q * (float)P;\n            if (stay > 0) nx.pr[x] += stay;\n            nx.score += (double)q * Q * reward;\n        } else if (y == x) {\n            nx.pr[x] += q;\n        } else {\n            float stay = q * (float)P;\n            float go = q * (float)Q;\n            if (stay > 0) nx.pr[x] += stay;\n            if (go > 0) nx.pr[y] += go;\n        }\n    }\n\n    double future = 0.0;\n    double sq = 0.0;\n    int nextStep = step + 1;\n    for (int x = 0; x < V; x++) {\n        double p = nx.pr[x];\n        if (p < 1e-12) continue;\n        future += p * adaptDP[nextStep][x];\n        sq += p * p;\n    }\n    nx.upper = nx.score + future;\n    nx.pri = nx.upper + 6.0 * sq;\n    return nx;\n}\n\nState applyPrefixState(const string& s) {\n    State st = initialState();\n    for (int step = 1; step <= (int)s.size(); step++) {\n        st = extendState(st, dirIndex(s[step - 1]), step);\n    }\n    return st;\n}\n\nState greedyComplete(State cur, bool usePri) {\n    for (int step = cur.len + 1; step <= MAXL; step++) {\n        State best;\n        bool first = true;\n        for (int a = 0; a < 4; a++) {\n            State nx = extendState(cur, a, step);\n            double key = usePri ? nx.pri : nx.upper;\n            if (first) {\n                best = std::move(nx);\n                first = false;\n            } else {\n                double bkey = usePri ? best.pri : best.upper;\n                if (key > bkey + 1e-12 ||\n                    (fabs(key - bkey) <= 1e-12 && nx.score > best.score)) {\n                    best = std::move(nx);\n                }\n            }\n        }\n        cur = std::move(best);\n    }\n    return cur;\n}\n\nstring completeByGreedy(const string& prefix, bool usePri) {\n    string pref = prefix;\n    if ((int)pref.size() > MAXL) pref.resize(MAXL);\n    State st = applyPrefixState(pref);\n    if (st.len == MAXL) return pref;\n    State full = greedyComplete(st, usePri);\n    return toString(full);\n}\n\ndouble evaluateString(const string& s) {\n    static double cur[V], nxt[V];\n    fill(cur, cur + V, 0.0);\n    cur[start_id] = 1.0;\n    double score = 0.0;\n\n    for (int step = 1; step <= (int)s.size(); step++) {\n        fill(nxt, nxt + V, 0.0);\n        int a = dirIndex(s[step - 1]);\n        double reward = 401.0 - step;\n\n        for (int x = 0; x < V; x++) {\n            double q = cur[x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                nxt[x] += q * P;\n                score += q * Q * reward;\n            } else if (y == x) {\n                nxt[x] += q;\n            } else {\n                nxt[x] += q * P;\n                nxt[y] += q * Q;\n            }\n        }\n        memcpy(cur, nxt, sizeof(double) * V);\n    }\n    return score;\n}\n\nvoid computeForwardDist(const string& s) {\n    for (int x = 0; x < V; x++) fwdDist[0][x] = 0.0;\n    fwdDist[0][start_id] = 1.0;\n\n    for (int step = 1; step <= MAXL; step++) {\n        int a = dirIndex(s[step - 1]);\n        for (int x = 0; x < V; x++) fwdDist[step][x] = 0.0;\n\n        for (int x = 0; x < V; x++) {\n            double q = fwdDist[step - 1][x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                fwdDist[step][x] += q * P;\n            } else if (y == x) {\n                fwdDist[step][x] += q;\n            } else {\n                fwdDist[step][x] += q * P;\n                fwdDist[step][y] += q * Q;\n            }\n        }\n    }\n}\n\n// Build a new string by one exact right-to-left best-response pass.\n// The produced score is exact for the produced string.\ndouble backwardPassConstruct(const string& s, string& ns) {\n    computeForwardDist(s);\n    ns = s;\n\n    double valNext[V], valCur[V];\n    for (int x = 0; x < V; x++) valNext[x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        double bestScore = -1e100;\n        double bestHit = -1.0;\n        int bestA = 0;\n\n        for (int a = 0; a < 4; a++) {\n            double sc = 0.0;\n            double hit = 0.0;\n            for (int x = 0; x < V; x++) {\n                double pr = fwdDist[step - 1][x];\n                if (pr < 1e-14) continue;\n                int y = nxtPos[x][a];\n                double lv = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n                sc += pr * lv;\n                if (y == target_id) hit += pr * Q;\n            }\n            if (sc > bestScore + 1e-12 ||\n                (fabs(sc - bestScore) <= 1e-12 && hit > bestHit + 1e-15)) {\n                bestScore = sc;\n                bestHit = hit;\n                bestA = a;\n            }\n        }\n\n        ns[step - 1] = DIRS[bestA];\n        for (int x = 0; x < V; x++) {\n            int y = nxtPos[x][bestA];\n            valCur[x] = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n        }\n        memcpy(valNext, valCur, sizeof(double) * V);\n    }\n\n    return valNext[start_id];\n}\n\ndouble localOptimize(string& s, int maxPasses, double endTime,\n                     const function<double()>& elapsed) {\n    double curScore = evaluateString(s);\n    for (int pass = 0; pass < maxPasses && elapsed() < endTime; pass++) {\n        string ns;\n        double newScore = backwardPassConstruct(s, ns);\n        if (newScore > curScore + 1e-12) {\n            s.swap(ns);\n            curScore = newScore;\n        } else {\n            break;\n        }\n    }\n    return curScore;\n}\n\nstring routeByPenalties(double turnPenalty, double unsafeTurnPenalty) {\n    static const double INF = 1e100;\n    const int S = V * 5; // lastdir 0..3, 4 = none\n    vector<double> dist(S, INF);\n    vector<int> prevState(S, -1), prevMove(S, -1);\n\n    using PDI = pair<double, int>;\n    priority_queue<PDI, vector<PDI>, greater<PDI>> pq;\n\n    int st = start_id * 5 + 4;\n    dist[st] = 0.0;\n    pq.push({0.0, st});\n\n    while (!pq.empty()) {\n        auto [cd, sid] = pq.top();\n        pq.pop();\n        if (cd != dist[sid]) continue;\n\n        int x = sid / 5;\n        int last = sid % 5;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n\n            double w = 1.0;\n            if (last < 4 && last != a) {\n                w += turnPenalty;\n                if (nxtPos[x][last] != x) w += unsafeTurnPenalty;\n            }\n\n            int nsid = y * 5 + a;\n            double nd = cd + w;\n            if (nd + 1e-12 < dist[nsid]) {\n                dist[nsid] = nd;\n                prevState[nsid] = sid;\n                prevMove[nsid] = a;\n                pq.push({nd, nsid});\n            }\n        }\n    }\n\n    double best = INF;\n    int goal = -1;\n    for (int last = 0; last < 5; last++) {\n        int sid = target_id * 5 + last;\n        if (dist[sid] < best) {\n            best = dist[sid];\n            goal = sid;\n        }\n    }\n    if (goal == -1 || best >= INF / 2) return \"\";\n\n    string path;\n    int cur = goal;\n    while (cur != st) {\n        path.push_back(DIRS[prevMove[cur]]);\n        cur = prevState[cur];\n    }\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nstring randomShortestPath(double straightBias, double wallBias) {\n    string path;\n    int cur = start_id;\n    int prev = 4;\n\n    while (cur != target_id) {\n        vector<int> cand;\n        vector<double> w;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[cur][a];\n            if (y == cur) continue;\n            if (distToTarget[y] != distToTarget[cur] - 1) continue;\n\n            double ww = 1.0;\n            if (a == prev) ww *= straightBias;\n            if (nxtPos[y][a] == y) ww *= wallBias;\n            ww *= 0.9 + 0.2 * rng.nextDouble();\n\n            cand.push_back(a);\n            w.push_back(ww);\n        }\n\n        if (cand.empty()) break;\n\n        double sum = 0.0;\n        for (double x : w) sum += x;\n        double r = rng.nextDouble() * sum;\n        int choose = cand.back();\n        for (int i = 0; i < (int)cand.size(); i++) {\n            if ((r -= w[i]) <= 0) {\n                choose = cand[i];\n                break;\n            }\n        }\n        path.push_back(DIRS[choose]);\n        cur = nxtPos[cur][choose];\n        prev = choose;\n    }\n    return path;\n}\n\nstring makeTemplate(const string& path, int baseRep, int preTurnBonus, int postTurnBonus) {\n    string s;\n    for (int i = 0; i < (int)path.size() && (int)s.size() < MAXL; i++) {\n        int rep = baseRep;\n        if (i + 1 < (int)path.size() && path[i] != path[i + 1]) rep += preTurnBonus;\n        if (i > 0 && path[i - 1] != path[i]) rep += postTurnBonus;\n        for (int k = 0; k < rep && (int)s.size() < MAXL; k++) s.push_back(path[i]);\n    }\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> P;\n    Q = 1.0 - P;\n    for (int i = 0; i < N; i++) cin >> hwall[i];\n    for (int i = 0; i < N - 1; i++) cin >> vwall[i];\n\n    start_id = id(si, sj);\n    target_id = id(ti, tj);\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\n    buildTransitions();\n    bfsTargetDist();\n    buildAdaptiveDP();\n\n    double bestScore = -1.0;\n    string bestAns;\n    unordered_set<string> tried;\n\n    auto submitCandidate = [&](string s, int passes) {\n        if ((int)s.size() < MAXL) s = completeByGreedy(s, true);\n        if ((int)s.size() > MAXL) s.resize(MAXL);\n        if ((int)s.size() < MAXL) s += string(MAXL - s.size(), 'D');\n        if (!tried.insert(s).second) return;\n\n        double sc = localOptimize(s, passes, 1.95, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    };\n\n    // Baseline greedy completions\n    {\n        State init = initialState();\n        State g1 = greedyComplete(init, false);\n        submitCandidate(toString(g1), 6);\n\n        State g2 = greedyComplete(init, true);\n        submitCandidate(toString(g2), 6);\n    }\n\n    // Path-based candidates: explicitly diversify by turn / unsafe-turn penalties\n    vector<pair<double, double>> penaltyList = {\n        {0.0, 0.0},\n        {0.3, 0.0},\n        {0.8, 0.0},\n        {1.5, 0.0},\n        {0.4, 1.0},\n        {0.8, 2.0},\n        {1.2, 3.0},\n        {2.0, 4.0}\n    };\n\n    vector<string> paths;\n    for (auto [tp, up] : penaltyList) {\n        string path = routeByPenalties(tp, up);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Randomized shortest paths\n    for (int k = 0; k < 8; k++) {\n        double sb = 1.5 + 1.0 * rng.nextDouble();\n        double wb = 1.2 + 1.5 * rng.nextDouble();\n        string path = randomShortestPath(sb, wb);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Path templates\n    for (const string& path : paths) {\n        submitCandidate(path, 5);\n        submitCandidate(makeTemplate(path, 2, 0, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 1), 5);\n        submitCandidate(makeTemplate(path, 2, 1, 0), 5);\n        if (P >= 0.30) submitCandidate(makeTemplate(path, 3, 0, 0), 4);\n        if (P >= 0.35) submitCandidate(makeTemplate(path, 2, 1, 1), 4);\n    }\n\n    // Beam search with pruning by current best score\n    {\n        vector<State> beam, cand;\n        beam.reserve(500);\n        cand.reserve(2500);\n        beam.push_back(initialState());\n\n        auto cmpState = [](const State& a, const State& b) {\n            if (fabs(a.pri - b.pri) > 1e-12) return a.pri > b.pri;\n            if (fabs(a.upper - b.upper) > 1e-12) return a.upper > b.upper;\n            return a.score > b.score;\n        };\n\n        for (int step = 1; step <= MAXL; step++) {\n            if (elapsed() > 1.15) break;\n\n            int width;\n            if (step <= 40) width = 360;\n            else if (step <= 100) width = 280;\n            else width = 220;\n\n            cand.clear();\n            for (const State& st : beam) {\n                if (st.upper + 1e-12 < bestScore) continue;\n                for (int a = 0; a < 4; a++) {\n                    State nx = extendState(st, a, step);\n                    if (nx.upper + 1e-12 < bestScore) continue;\n                    cand.push_back(std::move(nx));\n                }\n            }\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(cand.begin(), cand.begin() + width, cand.end(), cmpState);\n                cand.resize(width);\n            }\n            sort(cand.begin(), cand.end(), cmpState);\n            beam.swap(cand);\n\n            if (!beam.empty() && (step <= 20 || step % 12 == 0)) {\n                int tries = min<int>(3, beam.size());\n                for (int i = 0; i < tries; i++) {\n                    string s1 = completeByGreedy(toString(beam[i]), true);\n                    submitCandidate(s1, 4);\n                    if (elapsed() > 1.20) break;\n                }\n            }\n        }\n\n        int tries = min<int>(8, beam.size());\n        for (int i = 0; i < tries && elapsed() < 1.35; i++) {\n            string s = completeByGreedy(toString(beam[i]), true);\n            submitCandidate(s, 5);\n        }\n    }\n\n    // Re-optimize best once more\n    if (!bestAns.empty() && elapsed() < 1.50) {\n        string s = bestAns;\n        double sc = localOptimize(s, 8, 1.60, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    // Random perturb + re-optimize\n    while (elapsed() < 1.96 && !bestAns.empty()) {\n        string s = bestAns;\n\n        int mode = rng.nextInt(0, 2);\n        if (mode == 0) {\n            int m = rng.nextInt(1, 3);\n            for (int t = 0; t < m; t++) {\n                int pos = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.8) * MAXL));\n                s[pos] = DIRS[rng.nextInt(0, 3)];\n            }\n        } else if (mode == 1) {\n            int l = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.7) * MAXL));\n            int len = rng.nextInt(2, 8);\n            char c = DIRS[rng.nextInt(0, 3)];\n            for (int i = l; i < min(MAXL, l + len); i++) s[i] = c;\n        } else {\n            int l = rng.nextInt(0, MAXL - 1);\n            int r = rng.nextInt(l, min(MAXL - 1, l + 10));\n            for (int i = l; i <= r; i++) s[i] = DIRS[rng.nextInt(0, 3)];\n        }\n\n        double sc = localOptimize(s, 3, 1.96, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    if (bestAns.empty()) {\n        State init = initialState();\n        State g = greedyComplete(init, true);\n        bestAns = toString(g);\n    }\n\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc010":"#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    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int CELLS = N * N;\nstatic constexpr int SIDES = CELLS * 4;\n\nstatic constexpr int di[4] = {0, -1, 0, 1};\nstatic constexpr int dj[4] = {-1, 0, 1, 0};\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int ROT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nstatic constexpr int PARTNER[8][4] = {\n    {1, 0, -1, -1},   // 0\n    {3, -1, -1, 0},   // 1\n    {-1, -1, 3, 2},   // 2\n    {-1, 2, 1, -1},   // 3\n    {1, 0, 3, 2},     // 4\n    {3, 2, 1, 0},     // 5\n    {2, -1, 0, -1},   // 6\n    {-1, 3, -1, 1},   // 7\n};\n\nstruct Eval {\n    long long official = 0;\n    long long sumsq = 0;\n    int top1 = 0;\n    int top2 = 0;\n    int totalCycle = 0;\n    int loops = 0;\n    int broken = 0;\n    int conn = 0;\n};\n\nstruct Candidate {\n    array<uint8_t, CELLS> st{};\n    Eval ev;\n};\n\nstruct Solver {\n    array<string, N> input{};\n    array<uint8_t, CELLS> orig{};\n    uint8_t cand[CELLS][4]{};\n    uint8_t candCnt[CELLS]{};\n    int rotTo[8][8];\n    int mask[8];\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n    const double TIME_LIMIT = 1.95;\n\n    Solver() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng = XorShift64(seed);\n\n        memset(rotTo, -1, sizeof(rotTo));\n        for (int t = 0; t < 8; t++) {\n            int cur = t;\n            for (int k = 0; k < 4; k++) {\n                if (rotTo[t][cur] == -1) rotTo[t][cur] = k;\n                cur = ROT[cur];\n            }\n        }\n\n        for (int s = 0; s < 8; s++) {\n            int m = 0;\n            for (int d = 0; d < 4; d++) if (PARTNER[s][d] != -1) m |= (1 << d);\n            mask[s] = m;\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void read_input() {\n        for (int i = 0; i < N; i++) cin >> input[i];\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = input[i][j] - '0';\n                orig[p] = (uint8_t)t;\n                if (0 <= t && t <= 3) {\n                    candCnt[p] = 4;\n                    cand[p][0] = 0;\n                    cand[p][1] = 1;\n                    cand[p][2] = 2;\n                    cand[p][3] = 3;\n                } else if (t == 4 || t == 5) {\n                    candCnt[p] = 2;\n                    cand[p][0] = 4;\n                    cand[p][1] = 5;\n                } else {\n                    candCnt[p] = 2;\n                    cand[p][0] = 6;\n                    cand[p][1] = 7;\n                }\n            }\n        }\n    }\n\n    inline bool used(int s, int d) const {\n        return (mask[s] >> d) & 1;\n    }\n\n    inline uint8_t randCand(int pos) {\n        return cand[pos][rng.next_int(candCnt[pos])];\n    }\n\n    int localCellScore(const array<uint8_t, CELLS>& st, int pos, int ns) const {\n        int i = pos / N;\n        int j = pos % N;\n        int sc = 0;\n        int m = mask[ns];\n        for (int d = 0; d < 4; d++) {\n            bool u = (m >> d) & 1;\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (u) sc -= 3;\n            } else {\n                int np = ni * N + nj;\n                bool v = used(st[np], opp[d]);\n                if (u && v) sc += 2;\n                else if (u ^ v) sc -= 3;\n            }\n        }\n        return sc;\n    }\n\n    void localGreedy(array<uint8_t, CELLS>& st, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            bool changed = false;\n            for (int z = 0; z < CELLS; z++) {\n                int pos = order[z];\n                uint8_t cur = st[pos];\n                int bestSc = localCellScore(st, pos, cur);\n                uint8_t best = cur;\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == cur) continue;\n                    int sc = localCellScore(st, pos, ns);\n                    if (sc > bestSc || (sc == bestSc && rng.next_int(2) == 0)) {\n                        bestSc = sc;\n                        best = ns;\n                    }\n                }\n                if (best != cur) {\n                    st[pos] = best;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    Eval evaluate(const array<uint8_t, CELLS>& st) const {\n        Eval res;\n\n        // broken / local consistency\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int s = st[p];\n\n                if (j == 0 && used(s, 0)) { res.broken++; res.conn -= 3; }\n                if (i == 0 && used(s, 1)) { res.broken++; res.conn -= 3; }\n                if (j == N - 1 && used(s, 2)) { res.broken++; res.conn -= 3; }\n                if (i == N - 1 && used(s, 3)) { res.broken++; res.conn -= 3; }\n\n                if (j + 1 < N) {\n                    int q = i * N + (j + 1);\n                    bool a = used(st[p], 2);\n                    bool b = used(st[q], 0);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n                if (i + 1 < N) {\n                    int q = (i + 1) * N + j;\n                    bool a = used(st[p], 3);\n                    bool b = used(st[q], 1);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n            }\n        }\n\n        static uint8_t vis[SIDES];\n        static int stackv[SIDES];\n        memset(vis, 0, sizeof(vis));\n\n        for (int c = 0; c < CELLS; c++) {\n            int s = st[c];\n            for (int d = 0; d < 4; d++) {\n                if (!used(s, d)) continue;\n                int root = c * 4 + d;\n                if (vis[root]) continue;\n\n                int sp = 0;\n                stackv[sp++] = root;\n                vis[root] = 1;\n\n                int cnt = 0;\n                bool all2 = true;\n\n                while (sp) {\n                    int id = stackv[--sp];\n                    int cc = id >> 2;\n                    int dd = id & 3;\n                    int ss = st[cc];\n                    cnt++;\n\n                    int deg = 1;\n                    int i = cc / N;\n                    int j = cc % N;\n                    int ni = i + di[dd];\n                    int nj = j + dj[dd];\n                    bool ext = false;\n                    if (0 <= ni && ni < N && 0 <= nj && nj < N) {\n                        int nc = ni * N + nj;\n                        if (used(st[nc], opp[dd])) ext = true;\n                    }\n                    if (ext) deg++;\n                    if (deg != 2) all2 = false;\n\n                    int pd = PARTNER[ss][dd];\n                    int nid1 = cc * 4 + pd;\n                    if (!vis[nid1]) {\n                        vis[nid1] = 1;\n                        stackv[sp++] = nid1;\n                    }\n\n                    if (ext) {\n                        int nc = ni * N + nj;\n                        int nid2 = nc * 4 + opp[dd];\n                        if (!vis[nid2]) {\n                            vis[nid2] = 1;\n                            stackv[sp++] = nid2;\n                        }\n                    }\n                }\n\n                if (all2) {\n                    int len = cnt / 2;\n                    res.loops++;\n                    res.totalCycle += len;\n                    res.sumsq += 1LL * len * len;\n                    if (len > res.top1) {\n                        res.top2 = res.top1;\n                        res.top1 = len;\n                    } else if (len > res.top2) {\n                        res.top2 = len;\n                    }\n                }\n            }\n        }\n\n        if (res.loops >= 2) res.official = 1LL * res.top1 * res.top2;\n        else res.official = 0;\n        return res;\n    }\n\n    bool better(const Eval& a, const Eval& b) const {\n        if (a.official != b.official) return a.official > b.official;\n        if (a.top2 != b.top2) return a.top2 > b.top2;\n        if (a.top1 != b.top1) return a.top1 > b.top1;\n        if (a.sumsq != b.sumsq) return a.sumsq > b.sumsq;\n        if (a.totalCycle != b.totalCycle) return a.totalCycle > b.totalCycle;\n        if (a.conn != b.conn) return a.conn > b.conn;\n        if (a.broken != b.broken) return a.broken < b.broken;\n        return a.loops > b.loops;\n    }\n\n    array<uint8_t, CELLS> makeSeed(int mode) {\n        array<uint8_t, CELLS> st{};\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = orig[p];\n\n                if (mode == 0) {\n                    st[p] = orig[p];\n                } else if (mode == 1) {\n                    st[p] = randCand(p);\n                } else if (mode == 2) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 3) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 5 : 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 4) {\n                    if (t == 4 || t == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 5) {\n                    if (t == 4 || t == 5) st[p] = 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 6) {\n                    if (t == 6 || t == 7) st[p] = (j & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else if (mode == 7) {\n                    if (t == 6 || t == 7) st[p] = (i & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else {\n                    st[p] = randCand(p);\n                }\n            }\n        }\n        localGreedy(st, 6);\n        return st;\n    }\n\n    void exact1CellHill(array<uint8_t, CELLS>& st, Eval& cur, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            if (elapsed() > TIME_LIMIT) return;\n\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                if (elapsed() > TIME_LIMIT) return;\n\n                int pos = order[ii];\n                uint8_t old = st[pos];\n                uint8_t bestState = old;\n                Eval bestEv = cur;\n\n                int curLS = localCellScore(st, pos, old);\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == old) continue;\n\n                    int newLS = localCellScore(st, pos, ns);\n                    if (newLS + 10 < curLS) continue; // light pruning only\n\n                    st[pos] = ns;\n                    Eval ev = evaluate(st);\n                    if (better(ev, bestEv)) {\n                        bestEv = ev;\n                        bestState = ns;\n                    }\n                }\n\n                st[pos] = bestState;\n                if (bestState != old) {\n                    cur = bestEv;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool improveRandom2x2(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            int p[4] = {\n                i * N + j,\n                i * N + (j + 1),\n                (i + 1) * N + j,\n                (i + 1) * N + (j + 1)\n            };\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]], old3 = st[p[3]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2, b3 = old3;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        for (int d = 0; d < candCnt[p[3]]; d++) {\n                            st[p[3]] = cand[p[3]][d];\n                            Eval ev = evaluate(st);\n                            if (better(ev, bestEv)) {\n                                bestEv = ev;\n                                b0 = st[p[0]];\n                                b1 = st[p[1]];\n                                b2 = st[p[2]];\n                                b3 = st[p[3]];\n                            }\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n            st[p[3]] = b3;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n                st[p[3]] = old3;\n            }\n        }\n        return any;\n    }\n\n    bool improveRandomLine3(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            bool horizontal = rng.next_int(2) == 0;\n            int p[3];\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                p[0] = i * N + j;\n                p[1] = i * N + (j + 1);\n                p[2] = i * N + (j + 2);\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                p[0] = i * N + j;\n                p[1] = (i + 1) * N + j;\n                p[2] = (i + 2) * N + j;\n            }\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        Eval ev = evaluate(st);\n                        if (better(ev, bestEv)) {\n                            bestEv = ev;\n                            b0 = st[p[0]];\n                            b1 = st[p[1]];\n                            b2 = st[p[2]];\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n            }\n        }\n        return any;\n    }\n\n    void mutate(array<uint8_t, CELLS>& st) {\n        int style = rng.next_int(6);\n\n        if (style == 0) {\n            int k = 2 + rng.next_int(10);\n            for (int t = 0; t < k; t++) {\n                int p = rng.next_int(CELLS);\n                st[p] = randCand(p);\n            }\n        } else if (style == 1) {\n            int h = 2 + rng.next_int(4);\n            int w = 2 + rng.next_int(4);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    if (st[p] == 4) st[p] = 5;\n                    else if (st[p] == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                }\n            }\n        } else if (style == 2) {\n            int row = rng.next_int(N);\n            for (int j = 0; j < N; j++) {\n                int p = row * N + j;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 3) {\n            int col = rng.next_int(N);\n            for (int i = 0; i < N; i++) {\n                int p = i * N + col;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 4) {\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            int p[4] = {\n                i * N + j,\n                i * N + (j + 1),\n                (i + 1) * N + j,\n                (i + 1) * N + (j + 1)\n            };\n            for (int z = 0; z < 4; z++) st[p[z]] = randCand(p[z]);\n        } else {\n            bool horizontal = rng.next_int(2) == 0;\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 3; x++) st[i * N + (j + x)] = randCand(i * N + (j + x));\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                for (int x = 0; x < 3; x++) st[(i + x) * N + j] = randCand((i + x) * N + j);\n            }\n        }\n    }\n\n    void addElite(vector<Candidate>& elite, const Candidate& c, int limit = 6) {\n        elite.push_back(c);\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n        if ((int)elite.size() > limit) elite.resize(limit);\n    }\n\n    string solve() {\n        start_time = chrono::steady_clock::now();\n        vector<Candidate> elite;\n\n        // Raw original as one candidate\n        {\n            Candidate c;\n            c.st = orig;\n            c.ev = evaluate(c.st);\n            addElite(elite, c);\n        }\n\n        // Structured seeds\n        for (int mode = 0; mode <= 7; mode++) {\n            if (elapsed() > 0.35) break;\n            Candidate c;\n            c.st = makeSeed(mode);\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            improveRandomLine3(c.st, c.ev, 6);\n            improveRandom2x2(c.st, c.ev, 6);\n            addElite(elite, c);\n        }\n\n        // Random restarts\n        while (elapsed() < 0.75) {\n            Candidate c;\n            c.st = makeSeed(1 + rng.next_int(8));\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            addElite(elite, c);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        // Intensify elites\n        for (int id = 0; id < (int)elite.size(); id++) {\n            if (elapsed() > 1.10) break;\n            exact1CellHill(elite[id].st, elite[id].ev, 1);\n            improveRandomLine3(elite[id].st, elite[id].ev, 10);\n            improveRandom2x2(elite[id].st, elite[id].ev, 10);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        // Main perturb + refine loop\n        while (elapsed() < TIME_LIMIT) {\n            int idx;\n            int r = rng.next_int(100);\n            if (r < 50) idx = 0;\n            else if (r < 75) idx = min<int>(1, (int)elite.size() - 1);\n            else idx = rng.next_int((int)elite.size());\n\n            Candidate cur = elite[idx];\n            mutate(cur.st);\n            localGreedy(cur.st, 2);\n            cur.ev = evaluate(cur.st);\n\n            exact1CellHill(cur.st, cur.ev, 1);\n            improveRandomLine3(cur.st, cur.ev, 6 + rng.next_int(6));\n            improveRandom2x2(cur.st, cur.ev, 6 + rng.next_int(6));\n\n            addElite(elite, cur);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        const auto& best = elite[0].st;\n        string ans;\n        ans.reserve(CELLS);\n        for (int p = 0; p < CELLS; p++) {\n            int t = orig[p];\n            int s = best[p];\n            int r = rotTo[t][s];\n            if (r < 0) r = 0;\n            ans.push_back(char('0' + r));\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXM = 100;\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\nuint64_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 XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l));\n    }\n};\n\nint hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nchar opposite(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    if (c == 'R') return 'L';\n    return 0;\n}\n\nint next_pos(int empty, char mv, int N) {\n    if (mv == 'U') return empty - N;\n    if (mv == 'D') return empty + N;\n    if (mv == 'L') return empty - 1;\n    return empty + 1;\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int largestCC = 0;\n    int largestCCCycles = 0;\n    int cycleExcess = 0;\n    int matchedEdges = 0;\n    int bestPotential = 0;\n};\n\nstruct State {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    Metrics mt;\n};\n\nstruct Cand {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    Metrics mt;\n};\n\nstruct BestRef {\n    bool isTemp = false;\n    int nodeIdx = 0;\n    int parent = -1;\n    char lastMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Elite {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    char prevMove = 0;\n    int depth = 0;\n    string prefix;\n    Metrics mt;\n};\n\nMetrics evaluateBoard(const array<uint8_t, MAXM>& board, int N) {\n    static int pop4[16] = {\n        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4\n    };\n    int M = N * N;\n\n    static int md[MAXM];\n    static unsigned char vis[MAXM];\n    memset(md, 0, sizeof(int) * M);\n    memset(vis, 0, M);\n\n    auto hasMatch = [&](int a, int b, int abit, int bbit) -> bool {\n        return board[a] != 0 && board[b] != 0 && (board[a] & abit) && (board[b] & bbit);\n    };\n\n    int matchedHalf = 0;\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            if (board[id] == 0) continue;\n            if (c > 0 && hasMatch(id, id - 1, 1, 4)) md[id]++;\n            if (r > 0 && hasMatch(id, id - N, 2, 8)) md[id]++;\n            if (c + 1 < N && hasMatch(id, id + 1, 4, 1)) md[id]++;\n            if (r + 1 < N && hasMatch(id, id + N, 8, 2)) md[id]++;\n            matchedHalf += md[id];\n        }\n    }\n\n    Metrics mt;\n    mt.matchedEdges = matchedHalf / 2;\n\n    static int q[MAXM];\n    for (int s = 0; s < M; s++) {\n        if (board[s] == 0 || vis[s]) continue;\n\n        int head = 0, tail = 0;\n        q[tail++] = s;\n        vis[s] = 1;\n\n        int v = 0;\n        int sumMd = 0;\n\n        while (head < tail) {\n            int u = q[head++];\n            v++;\n            sumMd += md[u];\n            int r = u / N, c = u % N;\n\n            if (c > 0 && !vis[u - 1] && hasMatch(u, u - 1, 1, 4)) {\n                vis[u - 1] = 1;\n                q[tail++] = u - 1;\n            }\n            if (r > 0 && !vis[u - N] && hasMatch(u, u - N, 2, 8)) {\n                vis[u - N] = 1;\n                q[tail++] = u - N;\n            }\n            if (c + 1 < N && !vis[u + 1] && hasMatch(u, u + 1, 4, 1)) {\n                vis[u + 1] = 1;\n                q[tail++] = u + 1;\n            }\n            if (r + 1 < N && !vis[u + N] && hasMatch(u, u + N, 8, 2)) {\n                vis[u + N] = 1;\n                q[tail++] = u + N;\n            }\n        }\n\n        int e = sumMd / 2;\n        int cyc = max(0, e - v + 1);\n        mt.cycleExcess += cyc;\n\n        if (e == v - 1) mt.largestTree = max(mt.largestTree, v);\n\n        if (v > mt.largestCC || (v == mt.largestCC && cyc < mt.largestCCCycles)) {\n            mt.largestCC = v;\n            mt.largestCCCycles = cyc;\n        }\n\n        mt.bestPotential = max(mt.bestPotential, 4 * v - 7 * cyc);\n    }\n\n    return mt;\n}\n\nbool betterReal(const Metrics& a, int depthA, const Metrics& b, int depthB, int fullSize) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestTree == fullSize && depthA != depthB) return depthA < depthB;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.largestCCCycles != b.largestCCCycles) return a.largestCCCycles < b.largestCCCycles;\n    if (a.bestPotential != b.bestPotential) return a.bestPotential > b.bestPotential;\n    return false;\n}\n\nlong long keyTree(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 55) {\n        return 1'000'000'000'000LL * m.bestPotential\n             +   10'000'000'000LL * m.largestCC\n             +      100'000'000LL * m.matchedEdges\n             -        1'000'000LL * m.largestCCCycles\n             +           10'000LL * m.largestTree\n             -              100LL * m.cycleExcess;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   10'000'000'000LL * m.matchedEdges\n             -      100'000'000LL * m.cycleExcess\n             +        1'000'000LL * m.largestCC\n             -           10'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nlong long keyMatch(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   10'000'000'000LL * m.cycleExcess\n         +      100'000'000LL * m.largestCC\n         -        1'000'000LL * m.largestCCCycles\n         +           10'000LL * m.largestTree\n         +                1LL * m.bestPotential;\n}\n\nlong long keyFocus(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   20'000'000'000LL * m.cycleExcess\n         +      500'000'000LL * m.largestTree\n         +       10'000'000LL * m.largestCC\n         -          100'000LL * m.largestCCCycles\n         +                1LL * m.bestPotential;\n}\n\nlong long keyDedup(const Metrics& m, int depth, int T) {\n    return max(keyTree(m, depth, T), keyMatch(m));\n}\n\nlong long keyRoll(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 75) {\n        return 1'000'000'000'000LL * m.matchedEdges\n             -   15'000'000'000LL * m.cycleExcess\n             +      200'000'000LL * m.largestCC\n             +      100'000'000LL * m.largestTree\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   20'000'000'000LL * m.matchedEdges\n             -   30'000'000'000LL * m.cycleExcess\n             +      100'000'000LL * m.largestCC\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nstring reconstructPathFromNode(const vector<State>& nodes, int idx) {\n    string s;\n    while (idx > 0) {\n        s.push_back(nodes[idx].prevMove);\n        idx = nodes[idx].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    cin >> N >> T;\n    int M = N * N;\n    int FULL = M - 1;\n\n    array<uint8_t, MAXM> initBoard{};\n    int initEmpty = -1;\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            initBoard[i * N + j] = (uint8_t)v;\n            if (v == 0) initEmpty = i * N + j;\n        }\n    }\n\n    uint64_t zob[MAXM][16];\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < MAXM; i++) {\n        for (int j = 0; j < 16; j++) {\n            seed = splitmix64(seed);\n            zob[i][j] = seed;\n        }\n    }\n\n    uint64_t initHash = 0;\n    for (int i = 0; i < M; i++) initHash ^= zob[i][initBoard[i]];\n\n    Timer timer;\n    XorShift64 rng(initHash ^ 0x9e3779b97f4a7c15ULL);\n\n    State root;\n    root.board = initBoard;\n    root.hash = initHash;\n    root.empty = initEmpty;\n    root.parent = -1;\n    root.prevMove = 0;\n    root.mt = evaluateBoard(root.board, N);\n\n    if (root.mt.largestTree == FULL) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    int beamWidth1, beamWidth2;\n    double timeStage1, timeStage2, totalTimeLimit = 2.94;\n\n    if (N <= 7) {\n        beamWidth1 = 360;\n        beamWidth2 = 100;\n        timeStage1 = 1.95;\n        timeStage2 = 2.55;\n    } else if (N == 8) {\n        beamWidth1 = 300;\n        beamWidth2 = 84;\n        timeStage1 = 1.85;\n        timeStage2 = 2.50;\n    } else if (N == 9) {\n        beamWidth1 = 240;\n        beamWidth2 = 72;\n        timeStage1 = 1.75;\n        timeStage2 = 2.45;\n    } else {\n        beamWidth1 = 200;\n        beamWidth2 = 60;\n        timeStage1 = 1.65;\n        timeStage2 = 2.40;\n    }\n\n    vector<State> nodes;\n    nodes.reserve(1 + (beamWidth1 + beamWidth2) * (T + 5));\n    nodes.push_back(root);\n\n    vector<int> cur, nxt;\n    cur.push_back(0);\n\n    BestRef best;\n    best.isTemp = false;\n    best.nodeIdx = 0;\n    best.depth = 0;\n    best.mt = root.mt;\n\n    const char moves[4] = {'U', 'D', 'L', 'R'};\n    int depth = 0;\n\n    auto materializeAnswer = [&](const BestRef& b) -> string {\n        string ans;\n        if (b.isTemp) {\n            ans = reconstructPathFromNode(nodes, b.parent);\n            ans.push_back(b.lastMove);\n        } else {\n            ans = reconstructPathFromNode(nodes, b.nodeIdx);\n        }\n        if ((int)ans.size() > T) ans.resize(T);\n        return ans;\n    };\n\n    auto makeEliteFromNode = [&](int idx) -> Elite {\n        Elite e;\n        const State& s = nodes[idx];\n        e.board = s.board;\n        e.hash = s.hash;\n        e.empty = s.empty;\n        e.prevMove = s.prevMove;\n        e.prefix = reconstructPathFromNode(nodes, idx);\n        e.depth = (int)e.prefix.size();\n        e.mt = s.mt;\n        return e;\n    };\n\n    auto makeEliteFromBestRef = [&](const BestRef& b) -> Elite {\n        if (!b.isTemp) return makeEliteFromNode(b.nodeIdx);\n        Elite e;\n        const State& p = nodes[b.parent];\n        e.board = p.board;\n        e.hash = p.hash;\n        e.empty = p.empty;\n        e.prevMove = b.lastMove;\n        e.prefix = reconstructPathFromNode(nodes, b.parent);\n        e.prefix.push_back(b.lastMove);\n        e.depth = (int)e.prefix.size();\n\n        int np = next_pos(p.empty, b.lastMove, N);\n        uint8_t tile = e.board[np];\n        e.board[p.empty] = tile;\n        e.board[np] = 0;\n        e.empty = np;\n        e.hash = p.hash ^ zob[p.empty][0] ^ zob[np][tile] ^ zob[p.empty][tile] ^ zob[np][0];\n        e.mt = b.mt;\n        return e;\n    };\n\n    auto tryUpdateBestTemp = [&](const Metrics& mt, int nd, int parent, char mv) {\n        if (betterReal(mt, nd, best.mt, best.depth, FULL)) {\n            best.isTemp = true;\n            best.parent = parent;\n            best.lastMove = mv;\n            best.depth = nd;\n            best.mt = mt;\n        }\n    };\n\n    auto tryUpdateBestNode = [&](int nodeIdx, int nd) {\n        if (betterReal(nodes[nodeIdx].mt, nd, best.mt, best.depth, FULL)) {\n            best.isTemp = false;\n            best.nodeIdx = nodeIdx;\n            best.depth = nd;\n            best.mt = nodes[nodeIdx].mt;\n        }\n    };\n\n    // Stage 1: wide beam with two selection criteria.\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage1) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool foundFull = false;\n\n        for (int idx : cur) {\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                Cand cd;\n                cd.board = st.board;\n                uint8_t tile = cd.board[np];\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.hash = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, depth + 1, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    foundFull = true;\n                    break;\n                }\n\n                auto it = seen.find(cd.hash);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(cd.hash, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyDedup(cd.mt, depth + 1, T) > keyDedup(cands[pos].mt, depth + 1, T)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n            if (foundFull) break;\n        }\n\n        if (best.mt.largestTree == FULL) {\n            cout << materializeAnswer(best) << '\\n';\n            return 0;\n        }\n        if (cands.empty()) break;\n\n        int C = (int)cands.size();\n        vector<int> ordA(C), ordB(C);\n        iota(ordA.begin(), ordA.end(), 0);\n        iota(ordB.begin(), ordB.end(), 0);\n\n        sort(ordA.begin(), ordA.end(), [&](int x, int y) {\n            long long kx = keyTree(cands[x].mt, depth + 1, T);\n            long long ky = keyTree(cands[y].mt, depth + 1, T);\n            if (kx != ky) return kx > ky;\n            return keyMatch(cands[x].mt) > keyMatch(cands[y].mt);\n        });\n        sort(ordB.begin(), ordB.end(), [&](int x, int y) {\n            long long kx = keyMatch(cands[x].mt);\n            long long ky = keyMatch(cands[y].mt);\n            if (kx != ky) return kx > ky;\n            return keyTree(cands[x].mt, depth + 1, T) > keyTree(cands[y].mt, depth + 1, T);\n        });\n\n        vector<char> picked(C, 0);\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 4;\n\n        nxt.clear();\n        nxt.reserve(min(C, beamWidth1));\n\n        int pa = 0, pb = 0;\n        while ((int)nxt.size() < beamWidth1 && (pa < C || pb < C)) {\n            bool progressed = false;\n\n            while (pa < C) {\n                int id = ordA[pa++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid, depth + 1);\n                progressed = true;\n                break;\n            }\n            if ((int)nxt.size() >= beamWidth1) break;\n\n            while (pb < C) {\n                int id = ordB[pb++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid, depth + 1);\n                progressed = true;\n                break;\n            }\n\n            if (!progressed) break;\n        }\n\n        if ((int)nxt.size() < beamWidth1) {\n            for (int t = 0; t < C && (int)nxt.size() < beamWidth1; t++) {\n                int id = ordA[t];\n                if (picked[id]) continue;\n                picked[id] = 1;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid, depth + 1);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    if (best.mt.largestTree == FULL) {\n        cout << materializeAnswer(best) << '\\n';\n        return 0;\n    }\n\n    // Stage 2: focused beam.\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage2) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool foundFull = false;\n\n        for (int idx : cur) {\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                Cand cd;\n                cd.board = st.board;\n                uint8_t tile = cd.board[np];\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.hash = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, depth + 1, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    foundFull = true;\n                    break;\n                }\n\n                auto it = seen.find(cd.hash);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(cd.hash, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyFocus(cd.mt) > keyFocus(cands[pos].mt)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n            if (foundFull) break;\n        }\n\n        if (best.mt.largestTree == FULL) {\n            cout << materializeAnswer(best) << '\\n';\n            return 0;\n        }\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b) {\n            long long ka = keyFocus(a.mt);\n            long long kb = keyFocus(b.mt);\n            if (ka != kb) return ka > kb;\n            return keyTree(a.mt, depth + 1, T) > keyTree(b.mt, depth + 1, T);\n        });\n\n        nxt.clear();\n        nxt.reserve(min((int)cands.size(), beamWidth2));\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 2;\n\n        for (auto& cd : cands) {\n            if ((int)nxt.size() >= beamWidth2) break;\n            if (emptyCnt[cd.empty] >= perEmptyLimit) continue;\n            emptyCnt[cd.empty]++;\n\n            State ns;\n            ns.board = cd.board;\n            ns.hash = cd.hash;\n            ns.empty = cd.empty;\n            ns.parent = cd.parent;\n            ns.prevMove = cd.prevMove;\n            ns.mt = cd.mt;\n            int nid = (int)nodes.size();\n            nodes.push_back(std::move(ns));\n            nxt.push_back(nid);\n            tryUpdateBestNode(nid, depth + 1);\n        }\n\n        if (nxt.empty()) {\n            for (int i = 0; i < (int)cands.size() && (int)nxt.size() < beamWidth2; i++) {\n                State ns;\n                ns.board = cands[i].board;\n                ns.hash = cands[i].hash;\n                ns.empty = cands[i].empty;\n                ns.parent = cands[i].parent;\n                ns.prevMove = cands[i].prevMove;\n                ns.mt = cands[i].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid, depth + 1);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    Metrics bestMt = best.mt;\n    int bestDepth = best.depth;\n    string bestAns = materializeAnswer(best);\n\n    if (bestMt.largestTree == FULL) {\n        cout << bestAns << '\\n';\n        return 0;\n    }\n\n    // Collect elite states from final frontier + current best.\n    vector<Elite> elites;\n    {\n        vector<pair<long long, int>> ordF, ordT;\n        ordF.reserve(cur.size());\n        ordT.reserve(cur.size());\n        for (int idx : cur) {\n            ordF.push_back({keyFocus(nodes[idx].mt), idx});\n            ordT.push_back({keyTree(nodes[idx].mt, (int)reconstructPathFromNode(nodes, idx).size(), T), idx});\n        }\n        sort(ordF.begin(), ordF.end(), greater<>());\n        sort(ordT.begin(), ordT.end(), greater<>());\n\n        unordered_set<uint64_t> used;\n        used.reserve(32);\n\n        auto addNodeElite = [&](int idx) {\n            uint64_t h = nodes[idx].hash;\n            if (used.insert(h).second) elites.push_back(makeEliteFromNode(idx));\n        };\n\n        int takeF = min(6, (int)ordF.size());\n        int takeT = min(6, (int)ordT.size());\n        for (int i = 0; i < takeF; i++) addNodeElite(ordF[i].second);\n        for (int i = 0; i < takeT; i++) addNodeElite(ordT[i].second);\n\n        Elite eb = makeEliteFromBestRef(best);\n        if (used.insert(eb.hash).second) elites.push_back(std::move(eb));\n    }\n\n    if (elites.empty()) {\n        cout << bestAns << '\\n';\n        return 0;\n    }\n\n    auto eliteValue = [&](const Elite& e) {\n        return keyFocus(e.mt);\n    };\n\n    auto tryInsertElite = [&](const Elite& cand) {\n        for (auto& e : elites) {\n            if (e.hash == cand.hash) return;\n        }\n        if ((int)elites.size() < 16) {\n            elites.push_back(cand);\n            return;\n        }\n        int worst = 0;\n        for (int i = 1; i < (int)elites.size(); i++) {\n            if (eliteValue(elites[i]) < eliteValue(elites[worst])) worst = i;\n        }\n        if (eliteValue(cand) > eliteValue(elites[worst])) {\n            elites[worst] = cand;\n        }\n    };\n\n    struct Opt {\n        array<uint8_t, MAXM> board{};\n        uint64_t hash = 0;\n        int empty = 0;\n        char mv = 0;\n        Metrics mt;\n        long long key = 0;\n    };\n\n    while (timer.elapsed() < totalTimeLimit) {\n        sort(elites.begin(), elites.end(), [&](const Elite& a, const Elite& b) {\n            return eliteValue(a) > eliteValue(b);\n        });\n\n        int pool = min(8, (int)elites.size());\n        int pickElite = rng.next_int(0, pool);\n        if ((rng.next() & 3ULL) == 0) pickElite = 0; // often restart from best elite\n\n        Elite base = elites[pickElite];\n\n        array<uint8_t, MAXM> board = base.board;\n        uint64_t hash = base.hash;\n        int empty = base.empty;\n        char prevMove = base.prevMove;\n        Metrics curMt = base.mt;\n        string suffix;\n        suffix.reserve(max(0, T - base.depth));\n\n        long long curKey = keyRoll(curMt, base.depth, T);\n        int stagnation = 0;\n\n        uint64_t recent[16];\n        int recentLen = 1;\n        int recentPos = 1;\n        recent[0] = hash;\n\n        while (base.depth + (int)suffix.size() < T && timer.elapsed() < totalTimeLimit) {\n            vector<Opt> opts;\n            opts.reserve(4);\n\n            int r = empty / N, c = empty % N;\n\n            for (char mv : moves) {\n                if (prevMove && mv == opposite(prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = empty - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = empty + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = empty - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = empty + 1;\n                }\n\n                Opt op;\n                op.board = board;\n                uint8_t tile = op.board[np];\n                op.board[empty] = tile;\n                op.board[np] = 0;\n                op.empty = np;\n                op.mv = mv;\n                op.hash = hash ^ zob[empty][0] ^ zob[np][tile] ^ zob[empty][tile] ^ zob[np][0];\n                op.mt = evaluateBoard(op.board, N);\n                op.key = keyRoll(op.mt, base.depth + (int)suffix.size() + 1, T);\n\n                bool seenRecent = false;\n                for (int i = 0; i < recentLen; i++) {\n                    if (recent[i] == op.hash) {\n                        seenRecent = true;\n                        break;\n                    }\n                }\n                if (seenRecent) op.key -= 50'000'000LL;\n                op.key += (long long)(rng.next() % 2001) - 1000;\n                opts.push_back(std::move(op));\n            }\n\n            if (opts.empty()) break;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.key > b.key; });\n\n            int pick = 0;\n            uint64_t rv = rng.next() % 100;\n            if ((int)opts.size() >= 3) {\n                if (stagnation < 10) {\n                    if (rv < 78) pick = 0;\n                    else if (rv < 94) pick = 1;\n                    else pick = 2;\n                } else {\n                    if (rv < 55) pick = 0;\n                    else if (rv < 80) pick = 1;\n                    else if (rv < 92) pick = 2;\n                    else pick = rng.next_int(0, (int)opts.size());\n                }\n            } else if ((int)opts.size() == 2) {\n                if (stagnation < 10) pick = (rv < 82 ? 0 : 1);\n                else pick = (rv < 62 ? 0 : 1);\n            }\n\n            Opt chosen = std::move(opts[pick]);\n            board = chosen.board;\n            hash = chosen.hash;\n            empty = chosen.empty;\n            prevMove = chosen.mv;\n            curMt = chosen.mt;\n            suffix.push_back(chosen.mv);\n\n            recent[recentPos & 15] = hash;\n            recentPos++;\n            if (recentLen < 16) recentLen++;\n\n            long long nk = keyRoll(curMt, base.depth + (int)suffix.size(), T);\n            if (nk > curKey) stagnation = 0;\n            else stagnation++;\n            curKey = nk;\n\n            int totalDepth = base.depth + (int)suffix.size();\n            if (betterReal(curMt, totalDepth, bestMt, bestDepth, FULL)) {\n                bestMt = curMt;\n                bestDepth = totalDepth;\n                bestAns = base.prefix + suffix;\n                if ((int)bestAns.size() > T) bestAns.resize(T);\n                if (bestMt.largestTree == FULL) {\n                    cout << bestAns << '\\n';\n                    return 0;\n                }\n            }\n\n            if (stagnation >= 24 && (int)suffix.size() >= 8) break;\n        }\n\n        Elite ne;\n        ne.board = board;\n        ne.hash = hash;\n        ne.empty = empty;\n        ne.prevMove = prevMove;\n        ne.depth = base.depth + (int)suffix.size();\n        ne.prefix = base.prefix + suffix;\n        if ((int)ne.prefix.size() > T) ne.prefix.resize(T);\n        ne.mt = curMt;\n        tryInsertElite(ne);\n    }\n\n    if ((int)bestAns.size() > T) bestAns.resize(T);\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr double R = 10000.0;\nstatic constexpr int MAXK = 100;\n\nstruct Point {\n    int x, y;\n};\n\nstruct Part {\n    int m = 1;\n    vector<int> bin;              // strip index for each point\n    vector<long long> cuts;       // raw constants C of line A x + B y = C\n};\n\nstruct Sol {\n    int score = -1;\n    int goodCells = -1;\n    int dx = 1, dy = 0;           // family1 lines are parallel to (dx,dy)\n    int m1 = 1, m2 = 1;\n    vector<long long> cuts1, cuts2;\n};\n\nstatic inline bool better_pair(int sc, int good, int bestSc, int bestGood) {\n    if (sc != bestSc) return sc > bestSc;\n    return good > bestGood;\n}\nstatic inline bool better_sol(const Sol& a, const Sol& b) {\n    return better_pair(a.score, a.goodCells, b.score, b.goodCells);\n}\n\npair<int,int> normalize_dir(int dx, int dy) {\n    if (dx == 0 && dy == 0) return {1, 0};\n    int g = std::gcd(abs(dx), abs(dy));\n    dx /= g;\n    dy /= g;\n    if (dx < 0 || (dx == 0 && dy < 0)) {\n        dx = -dx;\n        dy = -dy;\n    }\n    return {dx, dy};\n}\n\nvector<pair<int,int>> generate_dirs_coarse() {\n    const double PI = acos(-1.0);\n    const int L = 997;\n    set<pair<int,int>> st;\n\n    for (int i = 0; i < 30; i++) {\n        double ang = PI * i / 30.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        st.insert(normalize_dir(dx, dy));\n    }\n\n    vector<pair<int,int>> extra = {\n        {1,0}, {0,1}, {1,1}, {2,1}, {1,2}, {3,1}, {1,3}, {3,2}, {2,3}\n    };\n    for (auto [dx,dy] : extra) st.insert(normalize_dir(dx,dy));\n    return vector<pair<int,int>>(st.begin(), st.end());\n}\n\nvector<pair<int,int>> generate_dirs_near(int bdx, int bdy) {\n    const double PI = acos(-1.0);\n    const int L = 2003;\n    set<pair<int,int>> st;\n\n    double base = atan2((double)bdy, (double)bdx);\n    vector<double> ds = {-3, -2, -1, -0.5, 0, 0.5, 1, 2, 3};\n\n    for (double deg : ds) {\n        double ang = base + deg * PI / 180.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        st.insert(normalize_dir(dx, dy));\n    }\n    st.insert(normalize_dir(bdx, bdy));\n    return vector<pair<int,int>>(st.begin(), st.end());\n}\n\nvector<double> select_lambdas(int N, const array<int,11>& a) {\n    vector<pair<double,double>> cand; // (approxScore, lambda)\n    for (double lam = 0.8; lam <= 10.0 + 1e-9; lam += 0.2) {\n        double Mocc = N / lam;\n        double p = exp(-lam);\n        double score = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lam / d;\n            double bd = Mocc * p;\n            score += min<double>(a[d], bd);\n        }\n        cand.push_back({score, lam});\n    }\n    sort(cand.begin(), cand.end(), [&](auto &l, auto &r) {\n        return l.first > r.first;\n    });\n\n    vector<double> res;\n    for (auto [sc, lam] : cand) {\n        bool ok = true;\n        for (double x : res) {\n            if (abs(x - lam) < 0.35) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res.push_back(lam);\n        if ((int)res.size() >= 5) break;\n    }\n    if (res.empty()) res.push_back(5.0);\n    return res;\n}\n\nvector<pair<int,int>> generate_pairs(int N, int A, const array<int,11>& a, int cap = 75) {\n    const double PI = acos(-1.0);\n    vector<double> lambdas = select_lambdas(N, a);\n    set<pair<int,int>> st;\n\n    auto add_pair = [&](int m1, int m2) {\n        if (m1 < 1 || m2 < 1) return;\n        if (m1 + m2 - 2 > MAXK) return;\n        st.insert({m1, m2});\n    };\n\n    for (double lam : lambdas) {\n        double P = 4.0 * N / (PI * lam);\n        vector<double> ratios = {1.0, 1.4, 1.0 / 1.4};\n\n        for (double ratio : ratios) {\n            int base1 = max(1, (int)llround(sqrt(P * ratio)));\n            for (int d1 = -2; d1 <= 2; d1++) {\n                int m1 = max(1, base1 + d1);\n                int base2 = max(1, (int)llround(P / m1));\n                for (int d2 = -1; d2 <= 1; d2++) {\n                    add_pair(m1, base2 + d2);\n                }\n            }\n        }\n    }\n\n    vector<int> oneD = {2,3,4,5,6,8,10,12,15,20,30,40,50,60,80,100};\n    for (int m : oneD) {\n        add_pair(1, m);\n        add_pair(m, 1);\n    }\n\n    {\n        double P = 4.0 * max(1, A) / PI;\n        int b = max(1, (int)llround(sqrt(P)));\n        for (int d1 = -3; d1 <= 3; d1++) {\n            int m1 = max(1, b + d1);\n            int m2 = max(1, (int)llround(P / m1));\n            for (int d2 = -2; d2 <= 2; d2++) add_pair(m1, m2 + d2);\n        }\n    }\n\n    vector<pair<int,int>> res(st.begin(), st.end());\n    sort(res.begin(), res.end(), [&](auto &L, auto &Rr) {\n        long long pL = 1LL * L.first * L.second;\n        long long pR = 1LL * Rr.first * Rr.second;\n        return pL > pR;\n    });\n    if ((int)res.size() > cap) res.resize(cap);\n    return res;\n}\n\nlong long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = 1; y = 0;\n        return a;\n    }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<long long,4> line_from_ABC(long long A, long long B, long long C) {\n    if (A == 0) {\n        long long y = C / B;\n        return {0, y, 1, y};\n    }\n    if (B == 0) {\n        long long x = C / A;\n        return {x, 0, x, 1};\n    }\n\n    long long x, y;\n    extgcd(llabs(A), llabs(B), x, y);\n    if (A < 0) x = -x;\n    if (B < 0) y = -y;\n\n    long long x0 = x * C;\n    long long y0 = y * C;\n\n    long double denom = (long double)A * A + (long double)B * B;\n    long double tt = ((long double)x0 * B - (long double)y0 * A) / denom;\n    long long t = llround(tt);\n\n    x0 -= B * t;\n    y0 += A * t;\n\n    long long x1 = x0, y1 = y0;\n    long long x2 = x0 - B, y2 = y0 + A;\n    return {x1, y1, x2, y2};\n}\n\nstruct DirData {\n    int dx, dy;\n    double len;\n    long long lim;\n    vector<long long> v1, v2;   // raw projections\n    vector<int> ord1, ord2;     // sorted order\n    vector<long long> s1, s2;   // sorted projections\n    vector<char> feas1, feas2;  // feasible boundary at rank p\n    unordered_set<long long> forb1, forb2;\n};\n\nDirData prepare_dir(const vector<Point>& pts, int dx, int dy) {\n    DirData D;\n    D.dx = dx;\n    D.dy = dy;\n    D.len = hypot((double)dx, (double)dy);\n    D.lim = (long long)floor(R * D.len - 1e-7);\n\n    int N = (int)pts.size();\n    D.v1.resize(N);\n    D.v2.resize(N);\n    D.ord1.resize(N);\n    D.ord2.resize(N);\n    D.forb1.reserve(N * 2 + 10);\n    D.forb2.reserve(N * 2 + 10);\n\n    for (int i = 0; i < N; i++) {\n        long long a = 1LL * (-dy) * pts[i].x + 1LL * dx * pts[i].y; // normal1\n        long long b = 1LL * dx * pts[i].x + 1LL * dy * pts[i].y;    // normal2\n        D.v1[i] = a;\n        D.v2[i] = b;\n        D.ord1[i] = i;\n        D.ord2[i] = i;\n        D.forb1.insert(a);\n        D.forb2.insert(b);\n    }\n\n    sort(D.ord1.begin(), D.ord1.end(), [&](int i, int j) {\n        if (D.v1[i] != D.v1[j]) return D.v1[i] < D.v1[j];\n        return i < j;\n    });\n    sort(D.ord2.begin(), D.ord2.end(), [&](int i, int j) {\n        if (D.v2[i] != D.v2[j]) return D.v2[i] < D.v2[j];\n        return i < j;\n    });\n\n    D.s1.resize(N);\n    D.s2.resize(N);\n    for (int i = 0; i < N; i++) {\n        D.s1[i] = D.v1[D.ord1[i]];\n        D.s2[i] = D.v2[D.ord2[i]];\n    }\n\n    D.feas1.assign(N + 1, 0);\n    D.feas2.assign(N + 1, 0);\n    for (int p = 1; p < N; p++) {\n        if (D.s1[p] - D.s1[p - 1] >= 2) D.feas1[p] = 1;\n        if (D.s2[p] - D.s2[p - 1] >= 2) D.feas2[p] = 1;\n    }\n    return D;\n}\n\nlong long adjust_constant(\n    long long target,\n    long long low,\n    long long high,\n    const unordered_set<long long>& forbidden\n) {\n    for (long long d = 0;; d++) {\n        long long c1 = target - d;\n        if (c1 >= low && c1 <= high && !forbidden.count(c1)) return c1;\n        if (d == 0) continue;\n        long long c2 = target + d;\n        if (c2 >= low && c2 <= high && !forbidden.count(c2)) return c2;\n    }\n}\n\nvoid build_bins_from_cuts(\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const vector<long long>& cuts,\n    vector<int>& bin\n) {\n    int N = (int)sortedVals.size();\n    bin.assign(N, 0);\n    int cur = 0, M = (int)cuts.size();\n    for (int r = 0; r < N; r++) {\n        while (cur < M && sortedVals[r] > cuts[cur]) cur++;\n        bin[ord[r]] = cur;\n    }\n}\n\nPart build_width_part(\n    int m,\n    double frac,\n    double len,\n    long long lim,\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const unordered_set<long long>& forbidden\n) {\n    Part part;\n    part.m = m;\n    int N = (int)sortedVals.size();\n\n    if (m == 1) {\n        part.bin.assign(N, 0);\n        return part;\n    }\n\n    double w = 2.0 * R / m;\n    vector<long long> cuts;\n    cuts.reserve(m - 1);\n\n    long long prev = -lim - 1;\n    for (int j = 0; j < m - 1; j++) {\n        double pos = -R + frac * w + j * w;\n        long long target = llround(pos * len);\n        long long c = adjust_constant(target, max(-lim + 1, prev + 1), lim - 1, forbidden);\n        cuts.push_back(c);\n        prev = c;\n    }\n\n    part.cuts = cuts;\n    build_bins_from_cuts(sortedVals, ord, part.cuts, part.bin);\n    return part;\n}\n\nstatic bool same_sol(const Sol& a, const Sol& b) {\n    return a.dx == b.dx && a.dy == b.dy &&\n           a.m1 == b.m1 && a.m2 == b.m2 &&\n           a.cuts1 == b.cuts1 && a.cuts2 == b.cuts2;\n}\n\nstatic void add_pool(vector<Sol>& pool, const Sol& cand, int limit) {\n    for (auto& x : pool) {\n        if (same_sol(x, cand)) {\n            if (better_sol(cand, x)) x = cand;\n            sort(pool.begin(), pool.end(), better_sol);\n            if ((int)pool.size() > limit) pool.resize(limit);\n            return;\n        }\n    }\n    pool.push_back(cand);\n    sort(pool.begin(), pool.end(), better_sol);\n    if ((int)pool.size() > limit) pool.resize(limit);\n}\n\nvoid try_eval_pair(\n    const Part& p1,\n    const Part& p2,\n    int dx,\n    int dy,\n    const array<int,11>& a,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    static int cnt[105 * 105];\n    int cells = p1.m * p2.m;\n    for (int i = 0; i < cells; i++) cnt[i] = 0;\n\n    int N = (int)p1.bin.size();\n    for (int i = 0; i < N; i++) {\n        cnt[p1.bin[i] * p2.m + p2.bin[i]]++;\n    }\n\n    int hist[11] = {};\n    int good = 0;\n    for (int i = 0; i < cells; i++) {\n        int c = cnt[i];\n        if (1 <= c && c <= 10) {\n            hist[c]++;\n            good++;\n        }\n    }\n\n    int sc = 0;\n    for (int d = 1; d <= 10; d++) sc += min(a[d], hist[d]);\n\n    Sol cand;\n    cand.score = sc;\n    cand.goodCells = good;\n    cand.dx = dx;\n    cand.dy = dy;\n    cand.m1 = p1.m;\n    cand.m2 = p2.m;\n    cand.cuts1 = p1.cuts;\n    cand.cuts2 = p2.cuts;\n\n    if (better_sol(cand, best)) best = cand;\n\n    if (pool) {\n        if ((int)pool->size() < poolLimit ||\n            better_pair(sc, good, pool->back().score, pool->back().goodCells)) {\n            add_pool(*pool, cand, poolLimit);\n        }\n    }\n}\n\nvoid search_with_dirs(\n    const vector<Point>& pts,\n    const array<int,11>& a,\n    const vector<pair<int,int>>& dirs,\n    const vector<pair<int,int>>& pairs,\n    const vector<double>& fracs,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    set<int> msset;\n    for (auto [m1, m2] : pairs) {\n        msset.insert(m1);\n        msset.insert(m2);\n    }\n    vector<int> ms(msset.begin(), msset.end());\n\n    for (auto [dx, dy] : dirs) {\n        DirData D = prepare_dir(pts, dx, dy);\n\n        vector<vector<Part>> parts1(102), parts2(102);\n\n        for (int m : ms) {\n            if (m == 1) {\n                parts1[m].push_back(build_width_part(1, 0.5, D.len, D.lim, D.s1, D.ord1, D.forb1));\n                parts2[m].push_back(build_width_part(1, 0.5, D.len, D.lim, D.s2, D.ord2, D.forb2));\n            } else {\n                for (double f : fracs) {\n                    parts1[m].push_back(build_width_part(m, f, D.len, D.lim, D.s1, D.ord1, D.forb1));\n                    parts2[m].push_back(build_width_part(m, f, D.len, D.lim, D.s2, D.ord2, D.forb2));\n                }\n            }\n        }\n\n        for (auto [m1, m2] : pairs) {\n            for (const auto& p1 : parts1[m1]) {\n                for (const auto& p2 : parts2[m2]) {\n                    try_eval_pair(p1, p2, dx, dy, a, best, pool, poolLimit);\n                }\n            }\n        }\n    }\n}\n\nstruct LocalOptimizer {\n    const DirData& D;\n    const array<int,11>& a;\n    int N, m1, m2;\n\n    vector<int> pos1, pos2;      // boundary ranks\n    vector<int> bin1, bin2;      // strip for each point\n    vector<int> cnt;             // cell counts\n    int hist[11]{};\n    int score = 0;\n    int good = 0;\n\n    LocalOptimizer(const DirData& D_, const array<int,11>& a_, int m1_, int m2_)\n        : D(D_), a(a_), N((int)D_.s1.size()), m1(m1_), m2(m2_) {}\n\n    static vector<int> cuts_to_pos(const vector<long long>& sortedVals, const vector<long long>& cuts) {\n        vector<int> pos;\n        pos.reserve(cuts.size());\n        for (long long c : cuts) {\n            int p = upper_bound(sortedVals.begin(), sortedVals.end(), c) - sortedVals.begin();\n            pos.push_back(p);\n        }\n        return pos;\n    }\n\n    static bool strictly_increasing(const vector<int>& pos) {\n        for (int i = 1; i < (int)pos.size(); i++) {\n            if (pos[i] <= pos[i - 1]) return false;\n        }\n        return true;\n    }\n\n    static vector<long long> pos_to_cuts(const vector<long long>& sortedVals, const vector<int>& pos) {\n        vector<long long> cuts;\n        cuts.reserve(pos.size());\n        for (int p : pos) {\n            long long L = sortedVals[p - 1];\n            long long U = sortedVals[p];\n            long long c = (L + U) / 2;\n            if (c <= L) c = L + 1;\n            if (c >= U) c = U - 1;\n            cuts.push_back(c);\n        }\n        return cuts;\n    }\n\n    void build_bins_from_pos(\n        const vector<int>& pos,\n        const vector<int>& ord,\n        vector<int>& bin\n    ) {\n        bin.assign(N, 0);\n        int cur = 0;\n        for (int r = 0; r < N; r++) {\n            while (cur < (int)pos.size() && r >= pos[cur]) cur++;\n            bin[ord[r]] = cur;\n        }\n    }\n\n    void rebuild_all() {\n        build_bins_from_pos(pos1, D.ord1, bin1);\n        build_bins_from_pos(pos2, D.ord2, bin2);\n\n        cnt.assign(m1 * m2, 0);\n        for (int d = 0; d <= 10; d++) hist[d] = 0;\n        score = 0;\n        good = 0;\n\n        for (int i = 0; i < N; i++) {\n            cnt[bin1[i] * m2 + bin2[i]]++;\n        }\n        for (int v : cnt) {\n            if (1 <= v && v <= 10) {\n                hist[v]++;\n                good++;\n            }\n        }\n        for (int d = 1; d <= 10; d++) score += min(a[d], hist[d]);\n    }\n\n    bool init_from_cuts(const vector<long long>& cuts1, const vector<long long>& cuts2) {\n        pos1 = cuts_to_pos(D.s1, cuts1);\n        pos2 = cuts_to_pos(D.s2, cuts2);\n        if (!strictly_increasing(pos1) || !strictly_increasing(pos2)) return false;\n        for (int p : pos1) if (!(1 <= p && p < N && D.feas1[p])) return false;\n        for (int p : pos2) if (!(1 <= p && p < N && D.feas2[p])) return false;\n        rebuild_all();\n        return true;\n    }\n\n    inline void remove_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] - 1) - min(a[v], hist[v]);\n            hist[v]--;\n            good--;\n        }\n    }\n\n    inline void add_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] + 1) - min(a[v], hist[v]);\n            hist[v]++;\n            good++;\n        }\n    }\n\n    inline void modify_cell(int idx, int delta) {\n        int oldv = cnt[idx];\n        int newv = oldv + delta;\n        remove_hist(oldv);\n        cnt[idx] = newv;\n        add_hist(newv);\n    }\n\n    bool optimize_cut1(int j) {\n        int old = pos1[j];\n        int prv = (j == 0 ? 0 : pos1[j - 1]);\n        int nxt = (j + 1 == (int)pos1.size() ? N : pos1[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n\n            int p = r + 1;\n            if (p < nxt && D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score;\n                    bestGood = good;\n                    bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n\n            int p = r;\n            if (D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score;\n                    bestGood = good;\n                    bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell((j + 1) * m2 + b, -1);\n                modify_cell(j * m2 + b, +1);\n                bin1[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell(j * m2 + b, -1);\n                modify_cell((j + 1) * m2 + b, +1);\n                bin1[id]++;\n            }\n        }\n        pos1[j] = bestp;\n        return true;\n    }\n\n    bool optimize_cut2(int j) {\n        int old = pos2[j];\n        int prv = (j == 0 ? 0 : pos2[j - 1]);\n        int nxt = (j + 1 == (int)pos2.size() ? N : pos2[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n\n            int p = r + 1;\n            if (p < nxt && D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score;\n                    bestGood = good;\n                    bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n\n            int p = r;\n            if (D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score;\n                    bestGood = good;\n                    bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + (j + 1), -1);\n                modify_cell(b * m2 + j, +1);\n                bin2[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + j, -1);\n                modify_cell(b * m2 + (j + 1), +1);\n                bin2[id]++;\n            }\n        }\n        pos2[j] = bestp;\n        return true;\n    }\n\n    void optimize(int rounds = 8) {\n        for (int it = 0; it < rounds; it++) {\n            bool changed = false;\n            if (it % 2 == 0) {\n                for (int j = 0; j < (int)pos1.size(); j++) changed |= optimize_cut1(j);\n                for (int j = 0; j < (int)pos2.size(); j++) changed |= optimize_cut2(j);\n            } else {\n                for (int j = (int)pos2.size() - 1; j >= 0; j--) changed |= optimize_cut2(j);\n                for (int j = (int)pos1.size() - 1; j >= 0; j--) changed |= optimize_cut1(j);\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<long long> final_cuts1() const { return pos_to_cuts(D.s1, pos1); }\n    vector<long long> final_cuts2() const { return pos_to_cuts(D.s2, pos2); }\n};\n\nvector<Sol> pick_unique_seeds(const vector<Sol>& pool, int limit) {\n    vector<Sol> res;\n    set<tuple<int,int,int,int>> used;\n    for (const auto& s : pool) {\n        auto key = make_tuple(s.dx, s.dy, s.m1, s.m2);\n        if (used.insert(key).second) {\n            res.push_back(s);\n            if ((int)res.size() >= limit) break;\n        }\n    }\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n\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 A = 0;\n    for (int d = 1; d <= 10; d++) A += a[d];\n\n    Sol best;\n    vector<Sol> pool;\n\n    // 1) Coarse search\n    auto coarseDirs = generate_dirs_coarse();\n    auto coarsePairs = generate_pairs(N, A, a, 72);\n    vector<double> coarseFracs = {0.25, 0.5, 0.75};\n    search_with_dirs(pts, a, coarseDirs, coarsePairs, coarseFracs, best, &pool, 16);\n\n    // 2) Refine around several top coarse candidates\n    auto seeds = pick_unique_seeds(pool, 3);\n    vector<double> fineFracs = {0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875};\n\n    for (const auto& sd : seeds) {\n        auto nearDirs = generate_dirs_near(sd.dx, sd.dy);\n        vector<pair<int,int>> nearPairs;\n        for (int m1 = max(1, sd.m1 - 1); m1 <= min(101, sd.m1 + 1); m1++) {\n            for (int m2 = max(1, sd.m2 - 1); m2 <= min(101, sd.m2 + 1); m2++) {\n                if (m1 + m2 - 2 <= MAXK) nearPairs.push_back({m1, m2});\n            }\n        }\n        search_with_dirs(pts, a, nearDirs, nearPairs, fineFracs, best, &pool, 24);\n    }\n\n    // 3) Local optimization on several best candidates\n    auto localSeeds = pick_unique_seeds(pool, 8);\n    for (const auto& sd : localSeeds) {\n        DirData D = prepare_dir(pts, sd.dx, sd.dy);\n        LocalOptimizer opt(D, a, sd.m1, sd.m2);\n        if (!opt.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n        opt.optimize(8);\n\n        Sol cand = sd;\n        cand.score = opt.score;\n        cand.goodCells = opt.good;\n        cand.cuts1 = opt.final_cuts1();\n        cand.cuts2 = opt.final_cuts2();\n\n        if (better_sol(cand, best)) best = cand;\n        add_pool(pool, cand, 24);\n    }\n\n    vector<array<long long,4>> out;\n    out.reserve(best.cuts1.size() + best.cuts2.size());\n\n    for (long long c : best.cuts1) {\n        out.push_back(line_from_ABC(-best.dy, best.dx, c));\n    }\n    for (long long c : best.cuts2) {\n        out.push_back(line_from_ABC(best.dx, best.dy, c));\n    }\n\n    if ((int)out.size() > K) out.resize(K);\n\n    cout << out.size() << '\\n';\n    for (auto &ln : out) {\n        cout << ln[0] << ' ' << ln[1] << ' ' << ln[2] << ' ' << ln[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int INF_PERIM = 1e9;\n\nusing Op = array<int, 8>;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : 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    double next_double() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\nstruct Cand {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n    int gain;\n    int perim;\n    int area;\n    double eval;\n};\n\nstruct EvalParams {\n    double beta;\n    double gamma;\n    double adjBonus;\n    int topKeep;\n    int pickTop;\n    double bias;\n    int maxPerim;\n};\n\nstruct Strategy {\n    vector<int> caps;\n    double betaHi, betaLo;\n    double gammaHi, gammaLo;\n    double adjHi, adjLo;\n    int topKeep;\n    int pickTop;\n    double bias;\n\n    // stage control\n    bool quotaMode;   // false: move to next cap only when current cap is exhausted\n    int stageLen;     // used if quotaMode = true\n};\n\nstruct State {\n    int N = 0;\n    int dotCount = 0;\n    uint8_t dot[MAXN][MAXN]{};\n    uint8_t H[MAXN][MAXN]{};   // (x,y) - (x+1,y)\n    uint8_t V[MAXN][MAXN]{};   // (x,y) - (x,y+1)\n    uint8_t D1[MAXN][MAXN]{};  // (x,y) - (x+1,y+1)\n    uint8_t D2[MAXN][MAXN]{};  // (x,y+1) - (x+1,y)\n    long long sumW = 0;\n    vector<Op> ops;\n};\n\nint N, M;\nint W[MAXN][MAXN];\nvector<int> cellOrder;\n\n// nearest occupied point in 8 directions\nint eastA[MAXN][MAXN], westA[MAXN][MAXN], northA[MAXN][MAXN], southA[MAXN][MAXN];\nint neA[MAXN][MAXN], nwA[MAXN][MAXN], seA[MAXN][MAXN], swA[MAXN][MAXN];\n\ninline int enc(int x, int y) { return (x << 6) | y; }\ninline int decx(int v) { return v >> 6; }\ninline int decy(int v) { return v & 63; }\ninline bool inside(int x, int y) { return 0 <= x && x < N && 0 <= y && y < N; }\ninline int sgn(int x) { return (x > 0) - (x < 0); }\n\ninline bool segment_used(const State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        int bx = min(x1, x2);\n        return st.H[bx][y1];\n    }\n    if (x1 == x2) {\n        int by = min(y1, y2);\n        return st.V[x1][by];\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D1[bx][by];\n    } else {\n        int bx = min(x1, x2), by = min(y1, y2);\n        return st.D2[bx][by];\n    }\n}\n\ninline void mark_segment(State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        st.H[min(x1, x2)][y1] = 1;\n        return;\n    }\n    if (x1 == x2) {\n        st.V[x1][min(y1, y2)] = 1;\n        return;\n    }\n    if ((x2 - x1) == (y2 - y1)) {\n        st.D1[min(x1, x2)][min(y1, y2)] = 1;\n    } else {\n        st.D2[min(x1, x2)][min(y1, y2)] = 1;\n    }\n}\n\ninline bool check_edge(const State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    if (len <= 0) return false;\n\n    int x = x1, y = y1;\n    for (int i = 1; i < len; i++) {\n        x += dx;\n        y += dy;\n        if (st.dot[x][y]) return false;\n    }\n\n    x = x1; y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        if (segment_used(st, x, y, nx, ny)) return false;\n        x = nx; y = ny;\n    }\n    return true;\n}\n\ninline void mark_edge(State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n\n    int x = x1, y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        mark_segment(st, x, y, nx, ny);\n        x = nx;\n        y = ny;\n    }\n}\n\ninline bool valid_rect(const State& st, const Cand& c) {\n    if (st.dot[c.x1][c.y1]) return false;\n    if (!st.dot[c.x2][c.y2] || !st.dot[c.x3][c.y3] || !st.dot[c.x4][c.y4]) return false;\n\n    if (!check_edge(st, c.x1, c.y1, c.x2, c.y2)) return false;\n    if (!check_edge(st, c.x2, c.y2, c.x3, c.y3)) return false;\n    if (!check_edge(st, c.x3, c.y3, c.x4, c.y4)) return false;\n    if (!check_edge(st, c.x4, c.y4, c.x1, c.y1)) return false;\n\n    return true;\n}\n\ninline void apply_move(State& st, const Cand& c) {\n    st.dot[c.x1][c.y1] = 1;\n    st.dotCount++;\n    st.sumW += W[c.x1][c.y1];\n\n    mark_edge(st, c.x1, c.y1, c.x2, c.y2);\n    mark_edge(st, c.x2, c.y2, c.x3, c.y3);\n    mark_edge(st, c.x3, c.y3, c.x4, c.y4);\n    mark_edge(st, c.x4, c.y4, c.x1, c.y1);\n\n    st.ops.push_back({c.x1, c.y1, c.x2, c.y2, c.x3, c.y3, c.x4, c.y4});\n}\n\ninline void push_top(vector<Cand>& best, const Cand& c, int K) {\n    if ((int)best.size() < K) {\n        best.push_back(c);\n        int i = (int)best.size() - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    } else if (c.eval > best.back().eval) {\n        best.back() = c;\n        int i = K - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    }\n}\n\ninline int adjacent_count8(const State& st, int x, int y) {\n    int cnt = 0;\n    for (int dx = -1; dx <= 1; dx++) {\n        int nx = x + dx;\n        if (nx < 0 || nx >= N) continue;\n        for (int dy = -1; dy <= 1; dy++) {\n            int ny = y + dy;\n            if (dy == 0 && dx == 0) continue;\n            if (ny < 0 || ny >= N) continue;\n            cnt += st.dot[nx][ny];\n        }\n    }\n    return cnt;\n}\n\nvoid build_nearest(const State& st) {\n    for (int y = 0; y < N; y++) {\n        int last = -1;\n        for (int x = 0; x < N; x++) {\n            westA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int x = N - 1; x >= 0; x--) {\n            eastA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        int last = -1;\n        for (int y = 0; y < N; y++) {\n            southA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int y = N - 1; y >= 0; y--) {\n            northA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            swA[x][y] = (x == 0 || y == 0) ? -1\n                : (st.dot[x - 1][y - 1] ? enc(x - 1, y - 1) : swA[x - 1][y - 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = N - 1; y >= 0; y--) {\n            neA[x][y] = (x == N - 1 || y == N - 1) ? -1\n                : (st.dot[x + 1][y + 1] ? enc(x + 1, y + 1) : neA[x + 1][y + 1]);\n        }\n    }\n    for (int x = 0; x < N; x++) {\n        for (int y = N - 1; y >= 0; y--) {\n            nwA[x][y] = (x == 0 || y == N - 1) ? -1\n                : (st.dot[x - 1][y + 1] ? enc(x - 1, y + 1) : nwA[x - 1][y + 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = 0; y < N; y++) {\n            seA[x][y] = (x == N - 1 || y == 0) ? -1\n                : (st.dot[x + 1][y - 1] ? enc(x + 1, y - 1) : seA[x + 1][y - 1]);\n        }\n    }\n}\n\nvector<Cand> collect_top_candidates(const State& st, const EvalParams& prm) {\n    build_nearest(st);\n\n    vector<Cand> best;\n    best.reserve(prm.topKeep);\n\n    const double maxAdjBonus = prm.adjBonus * 8.0;\n    const double minPenalty = prm.beta * 4.0 + prm.gamma * 1.0; // smallest rectangle: perim 4, area 1\n\n    auto try_add = [&](int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int adj) {\n        if (!inside(x3, y3)) return;\n        if (!st.dot[x3][y3]) return;\n\n        int l1 = max(abs(x2 - x1), abs(y2 - y1));\n        int l2 = max(abs(x4 - x1), abs(y4 - y1));\n        if (l1 <= 0 || l2 <= 0) return;\n\n        Cand c;\n        c.x1 = x1; c.y1 = y1;\n        c.x2 = x2; c.y2 = y2;\n        c.x3 = x3; c.y3 = y3;\n        c.x4 = x4; c.y4 = y4;\n        c.gain = W[x1][y1];\n        c.perim = 2 * (l1 + l2);\n        c.area = l1 * l2;\n        if (c.perim > prm.maxPerim) return;\n\n        c.eval = c.gain + prm.adjBonus * adj - prm.beta * c.perim - prm.gamma * c.area;\n\n        if (valid_rect(st, c)) push_top(best, c, prm.topKeep);\n    };\n\n    for (int id : cellOrder) {\n        int x = decx(id), y = decy(id);\n        if (st.dot[x][y]) continue;\n\n        if ((int)best.size() == prm.topKeep) {\n            double ub = W[x][y] + maxAdjBonus - minPenalty;\n            if (ub <= best.back().eval) break;\n        }\n\n        int e = eastA[x][y], w = westA[x][y], n = northA[x][y], s = southA[x][y];\n        int ne = neA[x][y], nw = nwA[x][y], se = seA[x][y], sw = swA[x][y];\n\n        // quick skip: if no possible direction pair, don't compute adjacency\n        bool possible =\n            (e != -1 && n != -1) || (e != -1 && s != -1) ||\n            (w != -1 && n != -1) || (w != -1 && s != -1) ||\n            (ne != -1 && nw != -1) || (ne != -1 && se != -1) ||\n            (sw != -1 && nw != -1) || (sw != -1 && se != -1);\n        if (!possible) continue;\n\n        int adj = adjacent_count8(st, x, y);\n\n        // Axis-aligned\n        if (e != -1 && n != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj);\n        }\n        if (e != -1 && s != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj);\n        }\n        if (w != -1 && n != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj);\n        }\n        if (w != -1 && s != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj);\n        }\n\n        // 45-degree\n        if (ne != -1 && nw != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj);\n        }\n        if (ne != -1 && se != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj);\n        }\n        if (sw != -1 && nw != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj);\n        }\n        if (sw != -1 && se != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj);\n        }\n    }\n\n    return best;\n}\n\nint choose_idx(const vector<Cand>& cand, int pickTop, double bias, XorShift64& rng) {\n    if (cand.empty()) return -1;\n    int m = min((int)cand.size(), pickTop);\n    if (m <= 1) return 0;\n    double r = rng.next_double();\n    int idx = (int)(pow(r, bias) * m);\n    if (idx >= m) idx = m - 1;\n    return idx;\n}\n\nState run_strategy(const State& initial, Strategy stg, XorShift64& rng,\n                   const function<double()>& elapsed, double TL, bool perturb) {\n    State st = initial;\n    st.ops.clear();\n    st.ops.reserve(N * N);\n\n    if (perturb) {\n        auto pert = [&](double v, double lo, double hi) {\n            return v * (lo + (hi - lo) * rng.next_double());\n        };\n        stg.betaHi = pert(stg.betaHi, 0.92, 1.08);\n        stg.betaLo = pert(stg.betaLo, 0.92, 1.08);\n        stg.gammaHi = pert(stg.gammaHi, 0.92, 1.08);\n        stg.gammaLo = pert(stg.gammaLo, 0.92, 1.08);\n        stg.adjHi = pert(stg.adjHi, 0.88, 1.12);\n        stg.adjLo = pert(stg.adjLo, 0.88, 1.12);\n        stg.bias = max(1.0, pert(stg.bias, 0.92, 1.08));\n        stg.pickTop = max(1, min(stg.topKeep, stg.pickTop + (int)(rng.next_u32() % 3) - 1));\n        if (stg.quotaMode) {\n            stg.stageLen = max(2, stg.stageLen + (int)(rng.next_u32() % 3) - 1);\n        }\n    }\n\n    int stage = 0;\n    int movesMade = 0;\n\n    while (elapsed() < TL) {\n        double prog = double(st.dotCount - M) / max(1, N * N - M);\n\n        EvalParams prm;\n        prm.beta = stg.betaHi * (1.0 - prog) + stg.betaLo * prog;\n        prm.gamma = stg.gammaHi * (1.0 - prog) + stg.gammaLo * prog;\n        prm.adjBonus = stg.adjHi * (1.0 - prog) + stg.adjLo * prog;\n        prm.topKeep = stg.topKeep;\n        prm.pickTop = stg.pickTop;\n        prm.bias = stg.bias;\n\n        vector<Cand> cand;\n\n        if (stg.quotaMode) {\n            int baseStage = min((int)stg.caps.size() - 1, movesMade / stg.stageLen);\n            bool found = false;\n            for (int s = baseStage; s < (int)stg.caps.size(); s++) {\n                prm.maxPerim = stg.caps[s];\n                cand = collect_top_candidates(st, prm);\n                if (!cand.empty()) {\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        } else {\n            if (stage >= (int)stg.caps.size()) stage = (int)stg.caps.size() - 1;\n            prm.maxPerim = stg.caps[stage];\n            cand = collect_top_candidates(st, prm);\n            if (cand.empty()) {\n                if (stage + 1 < (int)stg.caps.size()) {\n                    stage++;\n                    continue;\n                } else {\n                    break;\n                }\n            }\n        }\n\n        int idx = choose_idx(cand, prm.pickTop, prm.bias, rng);\n        apply_move(st, cand[idx]);\n        movesMade++;\n    }\n\n    return st;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State initial;\n    initial.N = N;\n\n    vector<pair<int, int>> initPts;\n    initPts.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        initial.dot[x][y] = 1;\n        initial.dotCount++;\n        initPts.push_back({x, y});\n    }\n\n    int c = (N - 1) / 2;\n    cellOrder.clear();\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            W[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n            cellOrder.push_back(enc(x, y));\n        }\n    }\n    sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n        int xa = decx(a), ya = decy(a);\n        int xb = decx(b), yb = decy(b);\n        if (W[xa][ya] != W[xb][yb]) return W[xa][ya] > W[xb][yb];\n        if (xa != xb) return xa < xb;\n        return ya < yb;\n    });\n\n    initial.sumW = 0;\n    for (auto [x, y] : initPts) initial.sumW += W[x][y];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    for (auto [x, y] : initPts) {\n        seed ^= (uint64_t)(x * 131 + y * 10007 + 17) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n    XorShift64 rng(seed);\n\n    vector<Strategy> strategies = {\n        // Exhaustive small-first\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.20, 0.18, 0.18, 0.020, 2.4, 0.4, 56, 5, 2.8, false, 0},\n        {{8, 12, 16, 24, INF_PERIM},    0.95, 0.12, 0.12, 0.010, 2.0, 0.2, 52, 4, 2.5, false, 0},\n        {{10, 14, 20, INF_PERIM},       0.70, 0.08, 0.08, 0.008, 1.4, 0.1, 44, 4, 2.2, false, 0},\n\n        // Balanced\n        {{INF_PERIM},                   0.45, 0.03, 0.040, 0.002, 0.8, 0.0, 40, 3, 2.0, false, 0},\n        {{18, 28, INF_PERIM},           0.35, 0.01, 0.020, 0.000, 0.5, 0.0, 40, 2, 1.7, false, 0},\n        {{INF_PERIM},                   0.18, 0.00, 0.010, 0.000, 0.2, 0.0, 32, 1, 1.0, false, 0},\n\n        // Quota/progress-based variants\n        {{8, 12, 16, 24, INF_PERIM},    1.00, 0.10, 0.12, 0.010, 1.8, 0.2, 48, 4, 2.3, true, 7},\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.30, 0.16, 0.20, 0.018, 2.2, 0.3, 56, 5, 2.7, true, 6},\n        {{10, 14, 20, INF_PERIM},       0.75, 0.06, 0.08, 0.006, 1.2, 0.1, 40, 3, 2.0, true, 8},\n    };\n\n    auto stTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - stTime).count();\n    };\n\n    const double TL = 4.80;\n\n    long long bestSum = initial.sumW;\n    vector<Op> bestOps;\n\n    // First: deterministic portfolio\n    for (int i = 0; i < (int)strategies.size() && elapsed() < TL * 0.45; i++) {\n        State st = run_strategy(initial, strategies[i], rng, elapsed, TL, false);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n    }\n\n    // Then: randomized portfolio\n    int turn = 0;\n    while (elapsed() < TL) {\n        Strategy stg = strategies[turn % strategies.size()];\n        State st = run_strategy(initial, stg, rng, elapsed, TL, true);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n        turn++;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto& op : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << op[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};\n\nstatic constexpr int N = 10;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\n// region ids\n// 0: TL, 1: TR, 2: BL, 3: BR, 4: BC\nstruct Board {\n    array<uint8_t, 100> a;\n    Board() { a.fill(0); }\n};\n\nstruct Solver {\n    array<int, 101> f{};\n    int total_cnt[4]{};\n    int rem_after[101][4]{}; // rem_after[t][c] = number of flavor c in turns t+1..100\n    Board board;\n\n    array<int, 4> target_region{}; // flavor 1..3 -> region id\n    int dist_table[5][100]{};\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver() {\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void init_dist() {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int idx = r * N + c;\n                dist_table[0][idx] = r + c;                         // TL\n                dist_table[1][idx] = r + (N - 1 - c);              // TR\n                dist_table[2][idx] = (N - 1 - r) + c;              // BL\n                dist_table[3][idx] = (N - 1 - r) + (N - 1 - c);    // BR\n                dist_table[4][idx] = (N - 1 - r) + min(abs(c - 4), abs(c - 5)); // BC\n            }\n        }\n    }\n\n    void read_input() {\n        uint64_t seed = 1469598103934665603ull;\n        for (int i = 1; i <= 100; i++) {\n            cin >> f[i];\n            total_cnt[f[i]]++;\n            seed ^= (uint64_t)(f[i] + 1009 * i);\n            seed *= 1099511628211ull;\n        }\n        rng = XorShift64(seed ^ 0x9e3779b97f4a7c15ull);\n        init_dist();\n\n        for (int c = 1; c <= 3; c++) rem_after[100][c] = 0;\n        for (int t = 99; t >= 0; t--) {\n            for (int c = 1; c <= 3; c++) rem_after[t][c] = rem_after[t + 1][c];\n            rem_after[t][f[t + 1]]++;\n        }\n    }\n\n    static inline void place(Board &b, int p, int flavor) {\n        int cnt = 0;\n        for (int i = 0; i < 100; i++) {\n            if (b.a[i] == 0) {\n                ++cnt;\n                if (cnt == p) {\n                    b.a[i] = (uint8_t)flavor;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline Board tilt(const Board &in, int dir) {\n        Board out;\n        if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                int wr = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr++ * N + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < N; c++) {\n                int wr = N - 1;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr-- * N + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = 0;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc++] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = N - 1;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc--] = v;\n                }\n            }\n        }\n        return out;\n    }\n\n    static inline int component_square_sum(const Board &b) {\n        bool vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; s++) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            int qh = 0, qt = 0;\n            q[qt++] = s;\n            vis[s] = true;\n            int sz = 0;\n\n            while (qh < qt) {\n                int v = q[qh++];\n                ++sz;\n                int r = v / N, c = v % N;\n\n                if (r > 0) {\n                    int nv = v - N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (r + 1 < N) {\n                    int nv = v + N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c + 1 < N) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    long long heuristic(const Board &b, int turn) const {\n        int rowcnt[10][4] = {};\n        int colcnt[10][4] = {};\n        int same_adj = 0, diff_adj = 0;\n        int dist_pen = 0;\n        int block_score = 0;\n\n        for (int idx = 0; idx < 100; idx++) {\n            uint8_t col = b.a[idx];\n            if (!col) continue;\n            int r = idx / N, c = idx % N;\n\n            rowcnt[r][col]++;\n            colcnt[c][col]++;\n\n            int mult = 1 + rem_after[turn][col] / 18;\n            dist_pen += dist_table[target_region[col]][idx] * mult;\n\n            if (c + 1 < N) {\n                uint8_t v = b.a[idx + 1];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t v = b.a[idx + N];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n        }\n\n        int purity = 0;\n        for (int i = 0; i < N; i++) {\n            for (int c = 1; c <= 3; c++) {\n                purity += rowcnt[i][c] * rowcnt[i][c];\n                purity += colcnt[i][c] * colcnt[i][c];\n            }\n        }\n\n        for (int r = 0; r + 1 < N; r++) {\n            for (int c = 0; c + 1 < N; c++) {\n                int cnt[4] = {};\n                uint8_t v1 = b.a[r * N + c];\n                uint8_t v2 = b.a[r * N + (c + 1)];\n                uint8_t v3 = b.a[(r + 1) * N + c];\n                uint8_t v4 = b.a[(r + 1) * N + (c + 1)];\n                if (v1) cnt[v1]++;\n                if (v2) cnt[v2]++;\n                if (v3) cnt[v3]++;\n                if (v4) cnt[v4]++;\n\n                int kinds = 0, occ = 0, sq = 0;\n                for (int col = 1; col <= 3; col++) {\n                    if (cnt[col]) {\n                        kinds++;\n                        occ += cnt[col];\n                        sq += cnt[col] * cnt[col];\n                    }\n                }\n                block_score += sq;\n                if (kinds >= 2) block_score -= 2 * occ * (kinds - 1);\n            }\n        }\n\n        int comp2 = component_square_sum(b);\n\n        int wComp = 28 + turn / 4;              // late game: stronger final-structure emphasis\n        int wSame = 16;\n        int wDiff = 13;\n        int wPurity = 2;\n        int wBlock = 5;\n        int wTarget = max(2, 19 - turn / 6);   // early game: stronger regional separation\n\n        long long val = 0;\n        val += 1LL * wComp * comp2;\n        val += 1LL * wSame * same_adj;\n        val -= 1LL * wDiff * diff_adj;\n        val += 1LL * wPurity * purity;\n        val += 1LL * wBlock * block_score;\n        val -= 1LL * wTarget * dist_pen;\n        return val;\n    }\n\n    long long value_after_tilt(const Board &b, int turn, int depth) {\n        if (turn == 100) {\n            return component_square_sum(b);\n        }\n        if (depth == 0) {\n            return heuristic(b, turn);\n        }\n\n        int empties = 100 - turn;\n        long long sum = 0;\n\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = value_after_tilt(nb, turn + 1, depth - 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n        return sum;\n    }\n\n    int choose_depth(int rem_future) const {\n        double t = elapsed();\n        if (t > 1.82) return 1;\n        if (rem_future <= 7 && t < 1.70) return 3;\n        if (rem_future <= 20 && t < 1.78) return 2;\n        return 1;\n    }\n\n    int greedy_dir_for_sim(const Board &b, int turn) {\n        long long best = LLONG_MIN;\n        int best_dir = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(b, dir);\n            long long v = heuristic(nb, turn);\n            if (v > best) {\n                best = v;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void choose_layout() {\n        vector<array<int, 3>> templates = {\n            {0, 1, 4}, // TL, TR, BC\n            {0, 1, 3}  // TL, TR, BR\n        };\n\n        const int TRIALS = 4;\n        int sampled_p[TRIALS][101]{};\n\n        for (int tr = 0; tr < TRIALS; tr++) {\n            for (int turn = 1; turn <= 100; turn++) {\n                int empties = 101 - turn;\n                sampled_p[tr][turn] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        long long best_total = -1;\n        array<int, 4> best_map = {0, 0, 1, 4};\n\n        array<int, 3> perm = {0, 1, 2};\n        for (auto tpl : templates) {\n            sort(perm.begin(), perm.end());\n            do {\n                array<int, 4> cand = {0, tpl[perm[0]], tpl[perm[1]], tpl[perm[2]]};\n                auto backup = target_region;\n                target_region = cand;\n\n                long long total = 0;\n                for (int tr = 0; tr < TRIALS; tr++) {\n                    Board b;\n                    for (int turn = 1; turn <= 100; turn++) {\n                        place(b, sampled_p[tr][turn], f[turn]);\n                        int dir = greedy_dir_for_sim(b, turn);\n                        b = tilt(b, dir);\n                    }\n                    total += component_square_sum(b);\n                }\n\n                target_region = backup;\n\n                if (total > best_total) {\n                    best_total = total;\n                    best_map = cand;\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n\n        target_region = best_map;\n    }\n\n    int decide_action(int turn) {\n        int rem_future = 100 - turn;\n        int depth = choose_depth(rem_future);\n\n        long long best = LLONG_MIN;\n        long long best_h = LLONG_MIN;\n        int best_dir = 0;\n\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(board, dir);\n            long long v = value_after_tilt(nb, turn, depth);\n            long long h = heuristic(nb, turn);\n            if (v > best || (v == best && h > best_h)) {\n                best = v;\n                best_h = h;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void solve() {\n        read_input();\n        choose_layout();\n\n        for (int turn = 1; turn <= 100; turn++) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place(board, p, f[turn]);\n            int dir = decide_action(turn);\n            board = tilt(board, dir);\n\n            cout << DIR_CH[dir] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ============================================================\n// Exact solver for eps = 0\n// ============================================================\n\nstruct ExactNoNoiseSolver {\n    int M, N, C;\n    vector<vector<int>> perm_maps;\n    vector<uint32_t> reps;\n    unordered_map<uint32_t, int> id_of;\n\n    static int unlabeled_count(int n) {\n        if (n == 4) return 11;\n        if (n == 5) return 34;\n        if (n == 6) return 156;\n        return 0;\n    }\n\n    static vector<pair<int,int>> edge_list(int n) {\n        vector<pair<int,int>> e;\n        for (int i = 0; i < n; ++i)\n            for (int j = i + 1; j < n; ++j)\n                e.push_back({i, j});\n        return e;\n    }\n\n    uint32_t permute_mask(uint32_t mask, const vector<int>& mp) const {\n        uint32_t res = 0;\n        while (mask) {\n            int b = __builtin_ctz(mask);\n            mask &= mask - 1;\n            res |= (1u << mp[b]);\n        }\n        return res;\n    }\n\n    uint32_t canonical(uint32_t mask) const {\n        uint32_t best = UINT32_MAX;\n        for (const auto& mp : perm_maps) {\n            uint32_t x = permute_mask(mask, mp);\n            if (x < best) best = x;\n        }\n        return best;\n    }\n\n    string mask_to_string(uint32_t mask) const {\n        string s;\n        s.reserve(C);\n        for (int i = 0; i < C; ++i) s.push_back(((mask >> i) & 1u) ? '1' : '0');\n        return s;\n    }\n\n    uint32_t string_to_mask(const string& s) const {\n        uint32_t mask = 0;\n        for (int i = 0; i < (int)s.size(); ++i) if (s[i] == '1') mask |= (1u << i);\n        return mask;\n    }\n\n    ExactNoNoiseSolver(int M_) : M(M_) {\n        if (M <= unlabeled_count(4)) N = 4;\n        else if (M <= unlabeled_count(5)) N = 5;\n        else N = 6;\n        C = N * (N - 1) / 2;\n\n        auto edges = edge_list(N);\n        vector<vector<int>> pos(N, vector<int>(N, -1));\n        for (int i = 0; i < C; ++i) {\n            auto [u, v] = edges[i];\n            pos[u][v] = pos[v][u] = i;\n        }\n\n        vector<int> p(N);\n        iota(p.begin(), p.end(), 0);\n        do {\n            vector<int> mp(C);\n            for (int i = 0; i < C; ++i) {\n                auto [u, v] = edges[i];\n                int a = p[u], b = p[v];\n                if (a > b) swap(a, b);\n                mp[i] = pos[a][b];\n            }\n            perm_maps.push_back(move(mp));\n        } while (next_permutation(p.begin(), p.end()));\n\n        set<uint32_t> seen;\n        uint32_t total = 1u << C;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            uint32_t can = canonical(mask);\n            if (seen.insert(can).second) reps.push_back(can);\n        }\n        sort(reps.begin(), reps.end());\n        reps.resize(M);\n        for (int i = 0; i < M; ++i) id_of[reps[i]] = i;\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (uint32_t m : reps) cout << mask_to_string(m) << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        uint32_t mask = string_to_mask(H);\n        uint32_t can = canonical(mask);\n        auto it = id_of.find(can);\n        if (it == id_of.end()) return 0;\n        return it->second;\n    }\n};\n\n// ============================================================\n// RNG\n// ============================================================\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    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// ============================================================\n// General solver\n// Equal-block threshold graphs + degree decoder + weak tie-break\n// ============================================================\n\nstruct GeneralSolver {\n    struct Candidate {\n        uint16_t mask;\n        vector<int> seq; // sorted block degree sequence, length R\n    };\n\n    struct ComboResult {\n        double proxy = -1.0;\n        int R = -1, B = -1, N = -1;\n        vector<Candidate> selected;\n    };\n\n    struct GraphCode {\n        uint16_t mask;\n        vector<int> ideal_deg;      // full sorted degree sequence, length N\n        vector<uint8_t> edgeBits;   // upper triangle\n        string gstr;\n    };\n\n    int M;\n    double eps, a, c;\n\n    int R, B, N, C;\n    vector<GraphCode> codes;\n    vector<int> eu, ev;\n\n    // Final decoder pack\n    int S;\n    int TOPL;\n    double mu_ideal;\n    double lambda_nd;\n    vector<vector<uint16_t>> feat_samples; // [M*S][2N]\n    vector<vector<float>> expected_deg;    // [M][N]\n\n    static int seq_dist2(const vector<int>& x, const vector<int>& y) {\n        int s = 0;\n        for (int i = 0; i < (int)x.size(); ++i) {\n            int d = x[i] - y[i];\n            s += d * d;\n        }\n        return s;\n    }\n\n    static vector<int> block_degree_seq(uint16_t mask, int R, int B) {\n        vector<int> deg(R);\n        int suf = 0;\n        for (int i = R - 1; i >= 0; --i) {\n            int z = (mask >> i) & 1u;\n            deg[i] = B * suf + (z ? (B - 1 + B * i) : 0);\n            suf += z;\n        }\n        sort(deg.begin(), deg.end());\n        return deg;\n    }\n\n    static string build_graph_string(uint16_t mask, int R, int B, vector<uint8_t>* edgeBits = nullptr) {\n        int N = R * B;\n        string g;\n        g.reserve(N * (N - 1) / 2);\n        if (edgeBits) edgeBits->clear(), edgeBits->reserve(N * (N - 1) / 2);\n\n        for (int u = 0; u < N; ++u) {\n            int bu = u / B;\n            for (int v = u + 1; v < N; ++v) {\n                int bv = v / B;\n                bool e;\n                if (bu == bv) e = ((mask >> bu) & 1u);\n                else e = ((mask >> max(bu, bv)) & 1u); // later block decides\n                g.push_back(e ? '1' : '0');\n                if (edgeBits) edgeBits->push_back((uint8_t)e);\n            }\n        }\n        return g;\n    }\n\n    double eval_proxy(const vector<Candidate>& sel, int B, int N) const {\n        double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n        double avg_p = 0.0;\n        const double SQRT2 = sqrt(2.0);\n\n        for (int i = 0; i < M; ++i) {\n            int best_d2 = INT_MAX;\n            for (int j = 0; j < M; ++j) if (i != j) {\n                best_d2 = min(best_d2, seq_dist2(sel[i].seq, sel[j].seq));\n            }\n            double p = 0.0;\n            if (sigma > 1e-15) {\n                double D = a * sqrt((double)B * best_d2);\n                double x = D / (2.0 * sigma);\n                p = 0.5 * erfc(x / SQRT2);\n            }\n            avg_p += p;\n        }\n        avg_p /= M;\n\n        double per_query = max(0.0, 1.0 - 0.1 * avg_p);\n        return pow(per_query, 100.0) / N;\n    }\n\n    vector<Candidate> greedy_select(const vector<Candidate>& cands, int start_idx) const {\n        int CC = (int)cands.size();\n        vector<int> minD(CC, INT_MAX);\n        vector<char> used(CC, 0);\n        vector<int> sel_idx;\n        sel_idx.reserve(M);\n\n        auto add_one = [&](int idx) {\n            used[idx] = 1;\n            sel_idx.push_back(idx);\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[idx].seq, cands[i].seq);\n                if (d2 < minD[i]) minD[i] = d2;\n            }\n        };\n\n        add_one(start_idx);\n        if (M >= 2) {\n            int far = -1, far_d = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[start_idx].seq, cands[i].seq);\n                if (d2 > far_d) far_d = d2, far = i;\n            }\n            add_one(far);\n        }\n\n        while ((int)sel_idx.size() < M) {\n            int best = -1, best_d = -1, best_sum = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int candd = minD[i];\n                int sumd = 0;\n                for (int x : sel_idx) sumd += seq_dist2(cands[i].seq, cands[x].seq);\n                if (candd > best_d || (candd == best_d && sumd > best_sum)) {\n                    best_d = candd;\n                    best_sum = sumd;\n                    best = i;\n                }\n            }\n            add_one(best);\n        }\n\n        vector<Candidate> sel;\n        sel.reserve(M);\n        for (int idx : sel_idx) sel.push_back(cands[idx]);\n        sort(sel.begin(), sel.end(), [](const Candidate& lhs, const Candidate& rhs) {\n            return lhs.seq < rhs.seq;\n        });\n        return sel;\n    }\n\n    ComboResult try_combo(int R, int B) const {\n        ComboResult res;\n        res.R = R;\n        res.B = B;\n        res.N = R * B;\n\n        map<vector<int>, uint16_t> uniq;\n        uint16_t total = (uint16_t)(1u << R);\n        for (uint16_t mask = 0; mask < total; ++mask) {\n            vector<int> seq = block_degree_seq(mask, R, B);\n            if (!uniq.count(seq)) uniq.emplace(seq, mask);\n        }\n\n        vector<Candidate> cands;\n        cands.reserve(uniq.size());\n        for (auto& kv : uniq) cands.push_back({kv.second, kv.first});\n        if ((int)cands.size() < M) return res;\n\n        int CC = (int)cands.size();\n        vector<int> sums(CC);\n        for (int i = 0; i < CC; ++i) {\n            sums[i] = accumulate(cands[i].seq.begin(), cands[i].seq.end(), 0);\n        }\n\n        int min_idx = 0, max_idx = 0;\n        for (int i = 1; i < CC; ++i) {\n            if (sums[i] < sums[min_idx]) min_idx = i;\n            if (sums[i] > sums[max_idx]) max_idx = i;\n        }\n\n        vector<pair<int,int>> ord;\n        ord.reserve(CC);\n        for (int i = 0; i < CC; ++i) ord.push_back({sums[i], i});\n        sort(ord.begin(), ord.end());\n        int med_idx = ord[CC / 2].second;\n\n        vector<int> starts = {min_idx, max_idx, med_idx};\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int st : starts) {\n            vector<Candidate> sel = greedy_select(cands, st);\n            double pr = eval_proxy(sel, B, R * B);\n            if (pr > res.proxy) {\n                res.proxy = pr;\n                res.selected = move(sel);\n            }\n        }\n        return res;\n    }\n\n    void prepare_pairs(int N_) {\n        N = N_;\n        C = N * (N - 1) / 2;\n        eu.clear();\n        ev.clear();\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n    }\n\n    static vector<uint16_t> sample_noisy_feature(\n        int N,\n        const vector<int>& eu,\n        const vector<int>& ev,\n        const vector<uint8_t>& edgeBits,\n        uint32_t thr,\n        SplitMix64& rng\n    ) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int C = (int)edgeBits.size();\n        for (int idx = 0; idx < C; ++idx) {\n            bool b = edgeBits[idx];\n            if (rng.next_u32() < thr) b = !b;\n            if (b) {\n                int u = eu[idx], v = ev[idx];\n                adj[u][v] = adj[v][u] = 1;\n                ++deg[u];\n                ++deg[v];\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static vector<uint16_t> feature_from_string(const string& H, int N) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int p = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                if (H[p++] == '1') {\n                    adj[i][j] = adj[j][i] = 1;\n                    ++deg[i];\n                    ++deg[j];\n                }\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static double degree_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int M,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg,\n        double mu_ideal\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i] - (int)s[2 * i]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        double ideal = 0.0;\n        for (int i = 0; i < N; ++i) ideal += fabs((double)qfeat[2 * i] - expected_deg[g][i]);\n\n        return avgBest + mu_ideal * ideal;\n    }\n\n    static double ndsum_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i + 1] - (int)s[2 * i + 1]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        return avgBest / max(1, N);\n    }\n\n    static int decode_feature(\n        const vector<uint16_t>& qfeat,\n        int M,\n        int S,\n        int N,\n        int TOPL,\n        double mu_ideal,\n        double lambda_nd,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg\n    ) {\n        vector<pair<double,int>> deg_rank;\n        deg_rank.reserve(M);\n        for (int g = 0; g < M; ++g) {\n            double dc = degree_cost_knn(qfeat, g, M, S, N, feat_samples, expected_deg, mu_ideal);\n            deg_rank.push_back({dc, g});\n        }\n\n        if (TOPL < M) {\n            nth_element(deg_rank.begin(), deg_rank.begin() + TOPL, deg_rank.end());\n            deg_rank.resize(TOPL);\n        }\n\n        int best_id = 0;\n        double best_cost = 1e300;\n\n        for (auto [dc, g] : deg_rank) {\n            double nc = ndsum_cost_knn(qfeat, g, S, N, feat_samples);\n            double total = dc + lambda_nd * nc;\n            if (total < best_cost) {\n                best_cost = total;\n                best_id = g;\n            }\n        }\n        return best_id;\n    }\n\n    vector<GraphCode> build_graph_codes_from_combo(const ComboResult& combo) const {\n        vector<GraphCode> ret;\n        ret.reserve(M);\n        int N = combo.R * combo.B;\n\n        for (const auto& cand : combo.selected) {\n            vector<uint8_t> bits;\n            string g = build_graph_string(cand.mask, combo.R, combo.B, &bits);\n\n            vector<int> ideal_deg;\n            ideal_deg.reserve(N);\n            for (int d : cand.seq) {\n                for (int t = 0; t < combo.B; ++t) ideal_deg.push_back(d);\n            }\n\n            ret.push_back({cand.mask, move(ideal_deg), move(bits), move(g)});\n        }\n        return ret;\n    }\n\n    static double validate_combo(\n        int M,\n        double eps,\n        const ComboResult& combo,\n        const vector<GraphCode>& codes\n    ) {\n        int N = combo.N;\n        int C = N * (N - 1) / 2;\n        vector<int> eu, ev;\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n\n        int S_train, T_val, TOPL;\n        double mu_ideal = 0.25;\n        double lambda_nd;\n        if (eps < 0.08) {\n            S_train = 4;\n            T_val = 2;\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            S_train = 6;\n            T_val = 2;\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            S_train = 8;\n            T_val = 2;\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n\n        vector<vector<uint16_t>> feat_samples(M * S_train);\n        vector<vector<float>> expected_deg(M, vector<float>(N));\n        double a = 1.0 - 2.0 * eps;\n        double c = eps * (N - 1);\n\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x1234567890abcdefULL + (uint64_t)N * 1009 + M * 17 + (uint64_t)(eps * 1000 + 0.5));\n\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S_train; ++t) {\n                feat_samples[g * S_train + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n\n        int correct = 0, total = 0;\n        for (int tg = 0; tg < M; ++tg) {\n            for (int tv = 0; tv < T_val; ++tv) {\n                auto q = sample_noisy_feature(N, eu, ev, codes[tg].edgeBits, thr, rng);\n                int pred = decode_feature(q, M, S_train, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n                if (pred == tg) ++correct;\n                ++total;\n            }\n        }\n\n        double acc = (double)correct / total;\n        return 100.0 * (1.0 - acc) * log(0.9) - log((double)N);\n    }\n\n    GeneralSolver(int M_, double eps_) : M(M_), eps(eps_) {\n        a = 1.0 - 2.0 * eps;\n        c = 0.0;\n\n        vector<ComboResult> pool;\n\n        int minR = 0;\n        while ((1u << minR) < (unsigned)M) ++minR;\n        minR = max(minR, 4);\n        int maxR = min(10, minR + 5);\n\n        for (int r = minR; r <= maxR; ++r) {\n            int maxB = 100 / r;\n            for (int b = 1; b <= maxB; ++b) {\n                ComboResult cur = try_combo(r, b);\n                if (cur.proxy > 0) pool.push_back(move(cur));\n            }\n        }\n\n        if (pool.empty()) {\n            // conservative fallback\n            R = minR;\n            B = 100 / R;\n            N = R * B;\n            prepare_pairs(N);\n\n            vector<Candidate> fallback;\n            for (int k = 0; k < M; ++k) {\n                uint16_t mask = (uint16_t)k;\n                fallback.push_back({mask, block_degree_seq(mask, R, B)});\n            }\n            sort(fallback.begin(), fallback.end(), [](const Candidate& x, const Candidate& y) {\n                return x.seq < y.seq;\n            });\n\n            ComboResult combo;\n            combo.R = R; combo.B = B; combo.N = N; combo.selected = fallback;\n            codes = build_graph_codes_from_combo(combo);\n        } else {\n            sort(pool.begin(), pool.end(), [](const ComboResult& x, const ComboResult& y) {\n                return x.proxy > y.proxy;\n            });\n\n            int checkTop = min<int>(8, pool.size());\n            int best_i = 0;\n            double best_val = -1e300;\n\n            for (int i = 0; i < checkTop; ++i) {\n                auto tmp_codes = build_graph_codes_from_combo(pool[i]);\n                double val = validate_combo(M, eps, pool[i], tmp_codes);\n                if (val > best_val) {\n                    best_val = val;\n                    best_i = i;\n                }\n            }\n\n            R = pool[best_i].R;\n            B = pool[best_i].B;\n            N = pool[best_i].N;\n            codes = build_graph_codes_from_combo(pool[best_i]);\n        }\n\n        prepare_pairs(N);\n        c = eps * (N - 1);\n\n        if (eps < 0.05) S = 8;\n        else if (eps < 0.15) S = 12;\n        else if (eps < 0.25) S = 16;\n        else S = 20;\n        if (M < 20) S += 4;\n        S = min(S, 24);\n\n        if (eps < 0.08) {\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n        mu_ideal = 0.25;\n\n        feat_samples.assign(M * S, {});\n        expected_deg.assign(M, vector<float>(N));\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) {\n                expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n            }\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x3141592653589793ULL + (uint64_t)N * 10007 + M * 911 + (uint64_t)(eps * 1000 + 0.5));\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S; ++t) {\n                feat_samples[g * S + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (const auto& code : codes) cout << code.gstr << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        auto qfeat = feature_from_string(H, N);\n        return decode_feature(qfeat, M, S, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n    }\n};\n\n// ============================================================\n// main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    if (fabs(eps) < 1e-12) {\n        ExactNoNoiseSolver solver(M);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        GeneralSolver solver(M, eps);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\nstatic const int MAXD = 30;\n\nstruct Solver {\n    struct Edge {\n        int u, v;\n        ll w;\n        int cell = 0;\n        double usage = 0.0;\n        ll detour = 0;\n        double imp = 1.0;\n    };\n    struct Adj {\n        int to, id;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<pair<int,int>> coord;\n    vector<vector<Adj>> g;\n    vector<int> degv;\n\n    // assignment\n    vector<int> dayOf;      // edge -> day [0..D-1]\n    vector<int> posInDay;\n    vector<vector<int>> dayEdges;\n    vector<int> quota;\n    vector<int> dayCnt;\n    vector<double> dayLoad;\n\n    // counts\n    vector<array<int, MAXD>> cntV;\n    vector<array<int, MAXD>> cntCell;\n\n    // conflict graph of dangerous edge pairs (mainly 2-edge-cuts)\n    vector<vector<int>> conflicts;\n    int bitBlocks;\n    vector<unsigned long long> confBitsFlat;\n    vector<array<int, MAXD>> confCnt; // confCnt[e][d] = #conflicting edges of e assigned to d\n\n    // geometry\n    int G, C;\n\n    // proxy weights\n    double WA, WB, WC;\n\n    // evaluation\n    vector<int> landmarks;\n    int L_imp = 12;\n    int L_eval = 4;\n    vector<vector<ll>> origEvalDist;\n    vector<ll> dayScore;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver() {\n        rng.seed((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    inline double comb2(int x) const {\n        return 0.5 * x * (x - 1);\n    }\n\n    inline int bit_index(int e, int b) const {\n        return e * bitBlocks + b;\n    }\n\n    inline bool is_conflict(int a, int b) const {\n        return (confBitsFlat[bit_index(a, b >> 6)] >> (b & 63)) & 1ULL;\n    }\n\n    void add_conflict(int a, int b) {\n        if (a == b) return;\n        if (is_conflict(a, b)) return;\n        confBitsFlat[bit_index(a, b >> 6)] |= 1ULL << (b & 63);\n        confBitsFlat[bit_index(b, a >> 6)] |= 1ULL << (a & 63);\n        conflicts[a].push_back(b);\n        conflicts[b].push_back(a);\n    }\n\n    void read_input() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        degv.assign(N, 0);\n\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            ll w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i] = {u, v, w};\n            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            degv[u]++;\n            degv[v]++;\n        }\n\n        coord.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> coord[i].first >> coord[i].second;\n        }\n\n        G = max(4, min(6, (int)llround(sqrt((double)D)) + 1));\n        C = G * G;\n\n        for (int i = 0; i < M; i++) {\n            double mx = (coord[edges[i].u].first + coord[edges[i].v].first) * 0.5;\n            double my = (coord[edges[i].u].second + coord[edges[i].v].second) * 0.5;\n            int cx = min(G - 1, max(0, (int)(mx * G / 1001.0)));\n            int cy = min(G - 1, max(0, (int)(my * G / 1001.0)));\n            edges[i].cell = cy * G + cx;\n        }\n\n        dayOf.assign(M, -1);\n        posInDay.assign(M, -1);\n        dayEdges.assign(D, {});\n        quota.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) quota[d]++;\n        dayCnt.assign(D, 0);\n        dayLoad.assign(D, 0.0);\n\n        cntV.assign(N, {});\n        for (auto &a : cntV) a.fill(0);\n\n        cntCell.assign(C, {});\n        for (auto &a : cntCell) a.fill(0);\n\n        conflicts.assign(M, {});\n        bitBlocks = (M + 63) >> 6;\n        confBitsFlat.assign(M * bitBlocks, 0ULL);\n        confCnt.assign(M, {});\n        for (auto &a : confCnt) a.fill(0);\n\n        WA = 0.025;\n        WB = 4.5;\n        WC = 0.6;\n    }\n\n    void dijkstra_full(int src,\n                       vector<ll> &dist,\n                       int skipEdge = -1,\n                       int skipDay = -1,\n                       int target = -1,\n                       vector<int> *parV = nullptr,\n                       vector<int> *parE = nullptr) {\n        dist.assign(N, INF64);\n        if (parV) parV->assign(N, -1);\n        if (parE) parE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n            if (v == target) return;\n\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == skipEdge) continue;\n                if (skipDay >= 0 && dayOf[id] == skipDay) continue;\n                int to = ad.to;\n                ll nd = cd + edges[id].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parV) (*parV)[to] = v;\n                    if (parE) (*parE)[to] = id;\n                    pq.push({nd, to});\n                } else if (parE && nd == dist[to]) {\n                    if ((*parE)[to] == -1 || id < (*parE)[to]) {\n                        (*parV)[to] = v;\n                        (*parE)[to] = id;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> choose_landmarks(int L) {\n        L = min(L, N);\n        vector<int> res;\n        res.reserve(L);\n\n        auto dist2 = [&](int a, int b) -> ll {\n            ll dx = coord[a].first - coord[b].first;\n            ll dy = coord[a].second - coord[b].second;\n            return dx * dx + dy * dy;\n        };\n\n        vector<ll> best(N, (1LL << 62));\n        int first = 0;\n        res.push_back(first);\n        for (int i = 0; i < N; i++) best[i] = dist2(i, first);\n\n        while ((int)res.size() < L) {\n            int cand = -1;\n            ll mx = -1;\n            for (int i = 0; i < N; i++) {\n                if (best[i] > mx) {\n                    mx = best[i];\n                    cand = i;\n                }\n            }\n            res.push_back(cand);\n            for (int i = 0; i < N; i++) best[i] = min(best[i], dist2(i, cand));\n        }\n        return res;\n    }\n\n    void compute_importance() {\n        landmarks = choose_landmarks(L_imp);\n        L_imp = (int)landmarks.size();\n        L_eval = min(L_eval, L_imp);\n        origEvalDist.assign(L_eval, vector<ll>(N, INF64));\n\n        vector<ll> dist;\n        vector<int> parV, parE;\n\n        for (int li = 0; li < L_imp; li++) {\n            int s = landmarks[li];\n            dijkstra_full(s, dist, -1, -1, -1, &parV, &parE);\n\n            if (li < L_eval) origEvalDist[li] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sz(N, 1);\n            for (int v : ord) {\n                if (v == s) continue;\n                int pe = parE[v];\n                int pv = parV[v];\n                if (pe >= 0) {\n                    edges[pe].usage += sz[v];\n                    sz[pv] += sz[v];\n                }\n            }\n        }\n\n        vector<ll> dist2;\n        for (int eid = 0; eid < M; eid++) {\n            int s = edges[eid].u;\n            int t = edges[eid].v;\n            dijkstra_full(s, dist2, eid, -1, t, nullptr, nullptr);\n            ll alt = dist2[t];\n            if (alt >= INF64 / 2) alt = (ll)1e18;\n            edges[eid].detour = max<ll>(0, alt - edges[eid].w);\n        }\n\n        double avgUsage = 0.0, avgDet = 0.0;\n        for (int i = 0; i < M; i++) {\n            avgUsage += edges[i].usage + 1.0;\n            avgDet += (double)edges[i].detour + 1.0;\n        }\n        avgUsage /= M;\n        avgDet /= M;\n\n        vector<double> raw(M);\n        double meanRaw = 0.0;\n        for (int i = 0; i < M; i++) {\n            double u = (edges[i].usage + 1.0) / avgUsage;\n            double d = ((double)edges[i].detour + 1.0) / avgDet;\n            raw[i] = u * d;\n            meanRaw += raw[i];\n        }\n        meanRaw /= M;\n        if (meanRaw <= 0) meanRaw = 1.0;\n\n        for (int i = 0; i < M; i++) {\n            edges[i].imp = raw[i] / meanRaw;\n        }\n    }\n\n    // Detect dangerous 2-edge-cut pairs\n    void compute_two_edge_cut_conflicts() {\n        vector<int> tin(N), low(N);\n        int timer = 0;\n\n        function<void(int,int,int, vector<int>&)> dfs = [&](int v, int pe, int banned, vector<int> &bridges) {\n            tin[v] = low[v] = timer++;\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == banned) continue;\n                if (id == pe) continue;\n                int to = ad.to;\n                if (tin[to] != -1) {\n                    low[v] = min(low[v], tin[to]);\n                } else {\n                    dfs(to, id, banned, bridges);\n                    low[v] = min(low[v], low[to]);\n                    if (low[to] > tin[v]) bridges.push_back(id);\n                }\n            }\n        };\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), -1);\n            fill(low.begin(), low.end(), -1);\n            timer = 0;\n            vector<int> bridges;\n\n            for (int s = 0; s < N; s++) {\n                if (tin[s] == -1) dfs(s, -1, banned, bridges);\n            }\n\n            for (int f : bridges) {\n                if (f > banned) add_conflict(banned, f);\n            }\n        }\n    }\n\n    inline bool touches(int eid, int v) const {\n        return edges[eid].u == v || edges[eid].v == v;\n    }\n\n    void add_edge_to_day(int eid, int d) {\n        dayOf[eid] = d;\n        posInDay[eid] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(eid);\n\n        dayCnt[d]++;\n        dayLoad[d] += edges[eid].imp;\n\n        cntV[edges[eid].u][d]++;\n        cntV[edges[eid].v][d]++;\n        cntCell[edges[eid].cell][d]++;\n\n        for (int f : conflicts[eid]) {\n            confCnt[f][d]++;\n        }\n    }\n\n    void remove_edge_from_day(int eid, int d) {\n        int pos = posInDay[eid];\n        int last = dayEdges[d].back();\n        dayEdges[d][pos] = last;\n        posInDay[last] = pos;\n        dayEdges[d].pop_back();\n\n        dayCnt[d]--;\n        dayLoad[d] -= edges[eid].imp;\n\n        cntV[edges[eid].u][d]--;\n        cntV[edges[eid].v][d]--;\n        cntCell[edges[eid].cell][d]--;\n\n        for (int f : conflicts[eid]) {\n            confCnt[f][d]--;\n        }\n\n        dayOf[eid] = -1;\n        posInDay[eid] = -1;\n    }\n\n    void move_edge_day(int eid, int nd) {\n        int od = dayOf[eid];\n        if (od == nd) return;\n        remove_edge_from_day(eid, od);\n        add_edge_to_day(eid, nd);\n    }\n\n    inline bool feasible_add_strict(int eid, int d) const {\n        if (dayCnt[d] >= quota[d]) return false;\n        if (confCnt[eid][d] > 0) return false;\n\n        const auto &e = edges[eid];\n        if (cntV[e.u][d] + 1 >= degv[e.u]) return false;\n        if (cntV[e.v][d] + 1 >= degv[e.v]) return false;\n\n        return true;\n    }\n\n    inline bool feasible_add_relaxed_vertex(int eid, int d) const {\n        if (dayCnt[d] >= quota[d]) return false;\n        if (confCnt[eid][d] > 0) return false;\n        return true;\n    }\n\n    inline double greedy_add_cost(int eid, int d) const {\n        const auto &e = edges[eid];\n        double x = e.imp;\n        double cost = 0.0;\n        cost += WA * (2.0 * dayLoad[d] * x + x * x);\n        cost += WB * (cntV[e.u][d] + cntV[e.v][d]);\n        cost += WC * cntCell[e.cell][d];\n        return cost;\n    }\n\n    void build_initial_solution() {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double sa = edges[a].imp * (1.0 + 0.18 * sqrt((double)conflicts[a].size() + 1.0));\n            double sb = edges[b].imp * (1.0 + 0.18 * sqrt((double)conflicts[b].size() + 1.0));\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        vector<int> days(D);\n        iota(days.begin(), days.end(), 0);\n\n        for (int eid : ord) {\n            shuffle(days.begin(), days.end(), rng);\n\n            double bestCost = 1e100;\n            int bestDay = -1;\n\n            for (int d : days) {\n                if (!feasible_add_strict(eid, d)) continue;\n                double c = greedy_add_cost(eid, d);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestDay = d;\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (!feasible_add_relaxed_vertex(eid, d)) continue;\n                    double c = greedy_add_cost(eid, d) + 1e5;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (dayCnt[d] >= quota[d]) continue;\n                    const auto &e = edges[eid];\n                    double c = greedy_add_cost(eid, d);\n                    c += 1e7 * confCnt[eid][d];\n                    if (cntV[e.u][d] + 1 >= degv[e.u]) c += 1e6;\n                    if (cntV[e.v][d] + 1 >= degv[e.v]) c += 1e6;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d = 0; d < D; d++) {\n                    if (dayCnt[d] < quota[d]) {\n                        bestDay = d;\n                        break;\n                    }\n                }\n            }\n\n            add_edge_to_day(eid, bestDay);\n        }\n    }\n\n    inline bool valid_swap_hard(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return false;\n\n        int ic = is_conflict(e1, e2) ? 1 : 0;\n        if (confCnt[e1][b] - ic > 0) return false;\n        if (confCnt[e2][a] - ic > 0) return false;\n\n        int vs[4] = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs, vs + 4);\n        int m = unique(vs, vs + 4) - vs;\n\n        for (int i = 0; i < m; i++) {\n            int v = vs[i];\n            int cntA = cntV[v][a];\n            int cntB = cntV[v][b];\n            int newA = cntA - (touches(e1, v) ? 1 : 0) + (touches(e2, v) ? 1 : 0);\n            int newB = cntB - (touches(e2, v) ? 1 : 0) + (touches(e1, v) ? 1 : 0);\n            if (newA >= degv[v]) return false;\n            if (newB >= degv[v]) return false;\n        }\n\n        return true;\n    }\n\n    double proxy_swap_delta(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return 0.0;\n\n        const auto &E1 = edges[e1];\n        const auto &E2 = edges[e2];\n        double delta = 0.0;\n\n        {\n            double la = dayLoad[a], lb = dayLoad[b];\n            double x = E1.imp, y = E2.imp;\n            double nla = la - x + y;\n            double nlb = lb - y + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n\n        {\n            int vs[4] = {E1.u, E1.v, E2.u, E2.v};\n            sort(vs, vs + 4);\n            int m = unique(vs, vs + 4) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][a];\n                int cb = cntV[v][b];\n                int da = 0;\n                if (touches(e1, v)) da--;\n                if (touches(e2, v)) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WB * add;\n        }\n\n        {\n            int cs[2] = {E1.cell, E2.cell};\n            sort(cs, cs + 2);\n            int m = unique(cs, cs + 2) - cs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int c = cs[i];\n                int ca = cntCell[c][a];\n                int cb = cntCell[c][b];\n                int da = 0;\n                if (E1.cell == c) da--;\n                if (E2.cell == c) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WC * add;\n        }\n\n        return delta;\n    }\n\n    void apply_swap(int e1, int e2) {\n        int d1 = dayOf[e1], d2 = dayOf[e2];\n        if (d1 == d2) return;\n        remove_edge_from_day(e1, d1);\n        remove_edge_from_day(e2, d2);\n        add_edge_to_day(e1, d2);\n        add_edge_to_day(e2, d1);\n    }\n\n    int pick_edge_from_day(int d, bool highImp) {\n        const auto &vec = dayEdges[d];\n        int sz = (int)vec.size();\n        if (sz == 0) return -1;\n        int best = vec[rng() % sz];\n        for (int t = 0; t < 3; t++) {\n            int cand = vec[rng() % sz];\n            if (highImp) {\n                if (edges[cand].imp > edges[best].imp) best = cand;\n            } else {\n                if (edges[cand].imp < edges[best].imp) best = cand;\n            }\n        }\n        return best;\n    }\n\n    bool day_connected(int blockedDay, vector<int> *compOut = nullptr) {\n        vector<int> comp;\n        if (compOut) {\n            compOut->assign(N, -1);\n            comp = *compOut;\n        } else {\n            comp.assign(N, -1);\n        }\n\n        int cc = 0;\n        queue<int> q;\n        for (int s = 0; s < N; s++) {\n            if (comp[s] != -1) continue;\n            comp[s] = cc;\n            q.push(s);\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                for (const auto &ad : g[v]) {\n                    if (dayOf[ad.id] == blockedDay) continue;\n                    int to = ad.to;\n                    if (comp[to] == -1) {\n                        comp[to] = cc;\n                        q.push(to);\n                    }\n                }\n            }\n            cc++;\n            if (!compOut && cc >= 2) return false;\n        }\n\n        if (compOut) *compOut = move(comp);\n        return cc == 1;\n    }\n\n    void proxy_local_search(double timeLimit) {\n        while (elapsed() < timeLimit) {\n            int a = rng() % D;\n            int b = rng() % D;\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n            if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n            if (!valid_swap_hard(e1, e2)) continue;\n\n            double delta = proxy_swap_delta(e1, e2);\n            if (delta < 0.0) {\n                apply_swap(e1, e2);\n            }\n        }\n    }\n\n    // Directly fix disconnected days\n    void repair_connectivity(double timeLimit) {\n        vector<int> comp;\n        while (elapsed() < timeLimit) {\n            int badDay = -1;\n            for (int d = 0; d < D; d++) {\n                if (!day_connected(d)) {\n                    badDay = d;\n                    break;\n                }\n            }\n            if (badDay == -1) break;\n\n            day_connected(badDay, &comp);\n\n            vector<int> candE;\n            candE.reserve(dayEdges[badDay].size());\n            for (int e : dayEdges[badDay]) {\n                if (comp[edges[e].u] != comp[edges[e].v]) candE.push_back(e);\n            }\n\n            if (candE.empty()) {\n                candE = dayEdges[badDay];\n            }\n\n            sort(candE.begin(), candE.end(), [&](int a, int b) {\n                return edges[a].imp > edges[b].imp;\n            });\n\n            bool improved = false;\n            double bestDelta = 1e100;\n            int bestE = -1, bestF = -1;\n\n            int limE = min((int)candE.size(), 30);\n            for (int ii = 0; ii < limE && elapsed() < timeLimit; ii++) {\n                int e = candE[ii];\n                for (int d2 = 0; d2 < D && elapsed() < timeLimit; d2++) {\n                    if (d2 == badDay) continue;\n\n                    // try a few randoms first\n                    vector<int> trialF;\n                    auto &vec = dayEdges[d2];\n                    if (vec.empty()) continue;\n\n                    int sample = min((int)vec.size(), 20);\n                    for (int t = 0; t < sample; t++) {\n                        trialF.push_back(vec[rng() % vec.size()]);\n                    }\n                    trialF.push_back(vec[0]);\n                    trialF.push_back(vec.back());\n\n                    sort(trialF.begin(), trialF.end());\n                    trialF.erase(unique(trialF.begin(), trialF.end()), trialF.end());\n\n                    for (int f : trialF) {\n                        if (!valid_swap_hard(e, f)) continue;\n                        double delta = proxy_swap_delta(e, f);\n                        if (delta > bestDelta + 5.0) continue;\n\n                        apply_swap(e, f);\n                        bool ok1 = day_connected(badDay);\n                        bool ok2 = day_connected(d2);\n                        apply_swap(f, e); // revert original swap\n\n                        if (ok1 && ok2) {\n                            if (delta < bestDelta) {\n                                bestDelta = delta;\n                                bestE = e;\n                                bestF = f;\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (improved) {\n                apply_swap(bestE, bestF);\n                continue;\n            }\n\n            // fallback: more exhaustive but only for one candidate\n            if (!candE.empty()) {\n                int e = candE[0];\n                for (int d2 = 0; d2 < D && elapsed() < timeLimit; d2++) {\n                    if (d2 == badDay) continue;\n                    for (int f : dayEdges[d2]) {\n                        if (!valid_swap_hard(e, f)) continue;\n                        apply_swap(e, f);\n                        bool ok1 = day_connected(badDay);\n                        bool ok2 = day_connected(d2);\n                        if (ok1 && ok2) {\n                            improved = true;\n                            break;\n                        }\n                        apply_swap(f, e);\n                    }\n                    if (improved) break;\n                }\n                if (improved) continue;\n            }\n\n            break;\n        }\n    }\n\n    ll eval_day_score(int blockedDay) {\n        vector<ll> dist;\n        ll total = 0;\n        for (int si = 0; si < L_eval; si++) {\n            dijkstra_full(landmarks[si], dist, -1, blockedDay, -1, nullptr, nullptr);\n            for (int v = 0; v < N; v++) {\n                ll dv = (dist[v] >= INF64 / 2 ? (ll)1e9 : dist[v]);\n                total += dv - origEvalDist[si][v];\n            }\n        }\n        return total;\n    }\n\n    void sampled_local_search(double timeLimit) {\n        dayScore.assign(D, 0);\n        for (int d = 0; d < D; d++) dayScore[d] = eval_day_score(d);\n\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n\n        int evalCnt = 0;\n        const int MAX_EVAL = 220;\n\n        while (elapsed() < timeLimit && evalCnt < MAX_EVAL) {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dayScore[a] > dayScore[b];\n            });\n\n            int topk = min(5, D);\n            int botk = min(5, D);\n            int a = ord[rng() % topk];\n            int b = ord[D - 1 - (rng() % botk)];\n            if (a == b) continue;\n            if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n            int e1 = pick_edge_from_day(a, true);\n            int e2 = pick_edge_from_day(b, false);\n            if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n            if (!valid_swap_hard(e1, e2)) continue;\n\n            double pdelta = proxy_swap_delta(e1, e2);\n            if (pdelta > 3.0 && (rng() & 3)) continue;\n\n            apply_swap(e1, e2);\n\n            // Never accept connectivity break\n            if (!day_connected(a) || !day_connected(b)) {\n                apply_swap(e2, e1);\n                continue;\n            }\n\n            ll na = eval_day_score(a);\n            ll nb = eval_day_score(b);\n            evalCnt++;\n\n            ll oldScore = dayScore[a] + dayScore[b];\n            ll newScore = na + nb;\n\n            if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                dayScore[a] = na;\n                dayScore[b] = nb;\n            } else {\n                apply_swap(e2, e1);\n            }\n        }\n    }\n\n    void solve() {\n        read_input();\n\n        compute_two_edge_cut_conflicts();\n        compute_importance();\n        build_initial_solution();\n\n        if (elapsed() < 1.9) {\n            repair_connectivity(1.9);\n        }\n        if (elapsed() < 2.8) {\n            proxy_local_search(2.8);\n        }\n        if (elapsed() < 3.8) {\n            repair_connectivity(3.8);\n        }\n        if (elapsed() < 5.75) {\n            sampled_local_search(5.75);\n        }\n        if (elapsed() < 5.95) {\n            repair_connectivity(5.95);\n        }\n    }\n\n    void output() {\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << (dayOf[i] + 1);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    solver.output();\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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp(int nL = 0, int nR = 0) : nL(nL), nR(nR), g(nL) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        bool found = false;\n        for (int u = 0; u < nL; ++u) {\n            if (pairU[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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\nstruct ObjData {\n    int D;\n    vector<string> f, r;\n    vector<vector<int>> Xs, Ys;\n    vector<int> Xmask, Ymask;\n};\n\nstruct OccCandidate {\n    vector<char> occ;\n    int V = 0;\n    string name;\n};\n\nstruct AnalysisResult {\n    int V = 0;\n    vector<int> occLins;\n    vector<pair<int,int>> doms;\n};\n\nstruct Block {\n    int size;\n    vector<int> cells;\n};\n\nstruct Partition {\n    int V = 0;\n    string name;\n    vector<Block> blocks;\n    vector<vector<int>> bySize; // indices in blocks by block size\n    vector<int> cnt;\n};\n\nstruct LayerState {\n    vector<int> cells2; // sorted x*D+y on one z layer\n};\n\nstruct PartitionSpec {\n    string name;\n    vector<int> phaseMasks; // bitmask over axes: x=1,y=2,z=4\n    vector<int> lens;\n    array<int,3> axisRank;  // smaller is preferred\n};\n\nstruct Solver {\n    int D;\n    ObjData obj[2];\n    Timer timer;\n\n    Solver(int D) : D(D) {}\n\n    int lin(int x, int y, int z) const {\n        return x * D * D + y * D + z;\n    }\n\n    tuple<int,int,int> invlin(int id) const {\n        int z = id % D;\n        id /= D;\n        int y = id % D;\n        int x = id / D;\n        return {x, y, z};\n    }\n\n    int lin2(int x, int y) const {\n        return x * D + y;\n    }\n\n    static int popcnt(int x) {\n        return __builtin_popcount((unsigned)x);\n    }\n\n    void prepare_obj(int idx, const vector<string>& f, const vector<string>& r) {\n        obj[idx].D = D;\n        obj[idx].f = f;\n        obj[idx].r = r;\n        obj[idx].Xs.assign(D, {});\n        obj[idx].Ys.assign(D, {});\n        obj[idx].Xmask.assign(D, 0);\n        obj[idx].Ymask.assign(D, 0);\n\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) {\n                if (f[z][x] == '1') {\n                    obj[idx].Xs[z].push_back(x);\n                    obj[idx].Xmask[z] |= (1 << x);\n                }\n            }\n            for (int y = 0; y < D; ++y) {\n                if (r[z][y] == '1') {\n                    obj[idx].Ys[z].push_back(y);\n                    obj[idx].Ymask[z] |= (1 << y);\n                }\n            }\n        }\n    }\n\n    AnalysisResult analyze_occ_for_domino(const vector<char>& occ) const {\n        AnalysisResult res;\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!occ[id]) continue;\n            res.occLins.push_back(id);\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) {\n                res.doms.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n            }\n        }\n        res.V = (int)res.occLins.size();\n        return res;\n    }\n\n    // ---------------- Cross construction ----------------\n\n    vector<char> build_cross_occ(const ObjData& o, const vector<pair<int,int>>& centers) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            int cx = centers[z].first;\n            int cy = centers[z].second;\n            for (int x : o.Xs[z]) occ[lin(x, cy, z)] = 1;\n            for (int y : o.Ys[z]) occ[lin(cx, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    int cross_transition_score(const ObjData& o, int z, pair<int,int> a, pair<int,int> b) const {\n        int xcap = popcnt(o.Xmask[z] & o.Xmask[z+1]);\n        int ycap = popcnt(o.Ymask[z] & o.Ymask[z+1]);\n        int s = 0;\n        if (a.second == b.second) s += xcap;\n        if (a.first  == b.first ) s += ycap;\n        if (a.first == b.first && a.second == b.second) s -= 1;\n        return s;\n    }\n\n    vector<vector<pair<int,int>>> make_cross_states(const ObjData& o) const {\n        vector<vector<pair<int,int>>> states(D);\n        for (int z = 0; z < D; ++z) {\n            for (int x : o.Xs[z]) for (int y : o.Ys[z]) states[z].push_back({x, y});\n        }\n        return states;\n    }\n\n    vector<vector<int>> cross_dp_scores(const ObjData& o, const vector<vector<pair<int,int>>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1e9);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int cand = dp[z-1][i] + cross_transition_score(o, z - 1, states[z - 1][i], states[z][j]);\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    vector<pair<int,int>> reconstruct_cross_path(const vector<vector<pair<int,int>>>& states, const vector<vector<int>>& prv, int lastIdx) const {\n        vector<pair<int,int>> centers(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            centers[z] = states[z][cur];\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n        return centers;\n    }\n\n    int local_overlap_score_cross(const ObjData& o, const vector<pair<int,int>>& centers, int z, pair<int,int> cand) const {\n        int s = 0;\n        if (z > 0) s += cross_transition_score(o, z - 1, centers[z - 1], cand);\n        if (z + 1 < D) s += cross_transition_score(o, z, cand, centers[z + 1]);\n        return s;\n    }\n\n    OccCandidate build_cross_local_from_centers(const ObjData& o, vector<pair<int,int>> centers, const string& name) const {\n        auto bestOcc = build_cross_occ(o, centers);\n        auto bestAna = analyze_occ_for_domino(bestOcc);\n\n        bool improved = true;\n        for (int pass = 0; pass < 2 && improved; ++pass) {\n            improved = false;\n            for (int z = 0; z < D; ++z) {\n                auto curCenter = centers[z];\n                int curMatch = (int)bestAna.doms.size();\n                int curTie = local_overlap_score_cross(o, centers, z, curCenter);\n\n                auto bestCenter = curCenter;\n                auto bestOccHere = bestOcc;\n                auto bestAnaHere = bestAna;\n                int bestMatch = curMatch;\n                int bestTie = curTie;\n\n                for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                    pair<int,int> cand = {x, y};\n                    if (cand == curCenter) continue;\n                    centers[z] = cand;\n                    auto occ = build_cross_occ(o, centers);\n                    auto ana = analyze_occ_for_domino(occ);\n                    int m = (int)ana.doms.size();\n                    int tie = local_overlap_score_cross(o, centers, z, cand);\n                    if (m > bestMatch || (m == bestMatch && tie > bestTie)) {\n                        bestMatch = m;\n                        bestTie = tie;\n                        bestCenter = cand;\n                        bestOccHere = move(occ);\n                        bestAnaHere = move(ana);\n                    }\n                }\n\n                centers[z] = bestCenter;\n                if (bestCenter != curCenter) {\n                    bestOcc = move(bestOccHere);\n                    bestAna = move(bestAnaHere);\n                    if (bestMatch > curMatch) improved = true;\n                }\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(bestOcc);\n        ret.V = bestAna.V;\n        ret.name = name;\n        return ret;\n    }\n\n    vector<OccCandidate> build_cross_candidates(const ObjData& o, const string& baseName, int topK = 3) const {\n        vector<OccCandidate> res;\n        auto states = make_cross_states(o);\n        vector<vector<int>> prv;\n        auto dp = cross_dp_scores(o, states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n\n        for (int t = 0; t < topK; ++t) {\n            auto centers = reconstruct_cross_path(states, prv, ord[t]);\n            OccCandidate c;\n            c.occ = build_cross_occ(o, centers);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = baseName + \"_dp\" + to_string(t);\n            res.push_back(move(c));\n        }\n\n        if (!ord.empty()) {\n            auto centers = reconstruct_cross_path(states, prv, ord[0]);\n            res.push_back(build_cross_local_from_centers(o, centers, baseName + \"_local\"));\n        }\n        return res;\n    }\n\n    // ---------------- Simple minimal constructions ----------------\n\n    vector<char> build_min_occ(const ObjData& o, bool rev) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            auto X = o.Xs[z];\n            auto Y = o.Ys[z];\n            int a = (int)X.size();\n            int b = (int)Y.size();\n\n            if (a >= b) {\n                if (rev) reverse(Y.begin(), Y.end());\n                for (int j = 0; j < b; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = b; j < a; ++j) occ[lin(X[j], Y[0], z)] = 1;\n            } else {\n                if (rev) reverse(X.begin(), X.end());\n                for (int j = 0; j < a; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = a; j < b; ++j) occ[lin(X[0], Y[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    // ---------------- Star minimal construction with richer states ----------------\n\n    vector<int> build_star_layer_cells(const ObjData& o, int z, bool anchorOnY, int anchorVal, bool rev, int offset) const {\n        vector<int> res;\n        auto X = o.Xs[z];\n        auto Y = o.Ys[z];\n        sort(X.begin(), X.end());\n        sort(Y.begin(), Y.end());\n\n        if (anchorOnY) {\n            int y0 = anchorVal;\n            vector<int> otherY;\n            for (int y : Y) if (y != y0) otherY.push_back(y);\n            if (rev) reverse(otherY.begin(), otherY.end());\n\n            int a = (int)X.size();\n            int k = (int)otherY.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int x = X[(offset + i) % a];\n                mp[x] = otherY[i];\n            }\n            for (int x : X) {\n                auto it = mp.find(x);\n                if (it == mp.end()) res.push_back(lin2(x, y0));\n                else res.push_back(lin2(x, it->second));\n            }\n        } else {\n            int x0 = anchorVal;\n            vector<int> otherX;\n            for (int x : X) if (x != x0) otherX.push_back(x);\n            if (rev) reverse(otherX.begin(), otherX.end());\n\n            int b = (int)Y.size();\n            int k = (int)otherX.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int y = Y[(offset + i) % b];\n                mp[y] = otherX[i];\n            }\n            for (int y : Y) {\n                auto it = mp.find(y);\n                if (it == mp.end()) res.push_back(lin2(x0, y));\n                else res.push_back(lin2(it->second, y));\n            }\n        }\n\n        sort(res.begin(), res.end());\n        res.erase(unique(res.begin(), res.end()), res.end());\n        return res;\n    }\n\n    vector<vector<LayerState>> make_star_states(const ObjData& o) const {\n        vector<vector<LayerState>> states(D);\n\n        for (int z = 0; z < D; ++z) {\n            set<vector<int>> seen;\n            int a = (int)o.Xs[z].size();\n            int b = (int)o.Ys[z].size();\n\n            if (a >= b) {\n                for (int y0 : o.Ys[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, a); ++off) {\n                            auto cells = build_star_layer_cells(o, z, true, y0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            } else {\n                for (int x0 : o.Xs[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, b); ++off) {\n                            auto cells = build_star_layer_cells(o, z, false, x0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            }\n        }\n\n        return states;\n    }\n\n    int overlap2d(const vector<int>& a, const vector<int>& b) const {\n        int i = 0, j = 0, cnt = 0;\n        while (i < (int)a.size() && j < (int)b.size()) {\n            if (a[i] == b[j]) {\n                ++cnt; ++i; ++j;\n            } else if (a[i] < b[j]) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        return cnt;\n    }\n\n    vector<vector<int>> star_dp_scores(const vector<vector<LayerState>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1e9);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int sc = overlap2d(states[z-1][i].cells2, states[z][j].cells2);\n                    int cand = dp[z-1][i] + sc;\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    OccCandidate reconstruct_star_occ(const vector<vector<LayerState>>& states, const vector<vector<int>>& prv, int lastIdx, const string& name) const {\n        vector<int> choice(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            choice[z] = cur;\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : states[z][choice[z]].cells2) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(occ);\n        ret.V = count(ret.occ.begin(), ret.occ.end(), 1);\n        ret.name = name;\n        return ret;\n    }\n\n    vector<OccCandidate> build_star_candidates(const ObjData& o, const string& baseName, int topK = 4) const {\n        vector<OccCandidate> res;\n        auto states = make_star_states(o);\n        vector<vector<int>> prv;\n        auto dp = star_dp_scores(states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n        for (int t = 0; t < topK; ++t) {\n            res.push_back(reconstruct_star_occ(states, prv, ord[t], baseName + \"_dp\" + to_string(t)));\n        }\n        return res;\n    }\n\n    // ---------------- Occupancy candidate generation ----------------\n\n    vector<OccCandidate> build_occ_candidates(const ObjData& o) const {\n        vector<OccCandidate> cands;\n\n        auto add_occ = [&](OccCandidate c) {\n            for (auto& e : cands) {\n                if (e.occ == c.occ) return;\n            }\n            cands.push_back(move(c));\n        };\n\n        for (auto& c : build_cross_candidates(o, \"cross\", 3)) add_occ(move(c));\n        for (auto& c : build_star_candidates(o, \"star\", 4)) add_occ(move(c));\n\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, false);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minA\";\n            add_occ(move(c));\n        }\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, true);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minB\";\n            add_occ(move(c));\n        }\n\n        return cands;\n    }\n\n    // ---------------- Partition into straight lines ----------------\n\n    bool cell_used(const vector<char>& unused, int x, int y, int z) const {\n        if (x < 0 || x >= D || y < 0 || y >= D || z < 0 || z >= D) return false;\n        return unused[lin(x, y, z)];\n    }\n\n    bool find_best_segment_mask(\n        const vector<char>& unused,\n        int L,\n        int allowedMask,\n        const array<int,3>& axisRank,\n        vector<int>& outCells\n    ) const {\n        const int dxs[3] = {1, 0, 0};\n        const int dys[3] = {0, 1, 0};\n        const int dzs[3] = {0, 0, 1};\n\n        bool found = false;\n        int bestExt = 1e9, bestRank = 1e9, bestPerp = 1e9, bestKey = 1e9;\n        vector<int> bestCells;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (!unused[lin(x, y, z)]) continue;\n\n            for (int dir = 0; dir < 3; ++dir) {\n                int bit = 1 << dir;\n                if (!(allowedMask & bit)) continue;\n\n                int dx = dxs[dir], dy = dys[dir], dz = dzs[dir];\n                int ex = x + (L - 1) * dx;\n                int ey = y + (L - 1) * dy;\n                int ez = z + (L - 1) * dz;\n                if (ex < 0 || ex >= D || ey < 0 || ey >= D || ez < 0 || ez >= D) continue;\n\n                vector<int> cells;\n                bool ok = true;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    int id = lin(nx, ny, nz);\n                    if (!unused[id]) { ok = false; break; }\n                    cells.push_back(id);\n                }\n                if (!ok) continue;\n\n                int ext = 0;\n                if (cell_used(unused, x - dx, y - dy, z - dz)) ++ext;\n                if (cell_used(unused, ex + dx, ey + dy, ez + dz)) ++ext;\n\n                int perp = 0;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    if (dir != 0) {\n                        perp += cell_used(unused, nx - 1, ny, nz);\n                        perp += cell_used(unused, nx + 1, ny, nz);\n                    }\n                    if (dir != 1) {\n                        perp += cell_used(unused, nx, ny - 1, nz);\n                        perp += cell_used(unused, nx, ny + 1, nz);\n                    }\n                    if (dir != 2) {\n                        perp += cell_used(unused, nx, ny, nz - 1);\n                        perp += cell_used(unused, nx, ny, nz + 1);\n                    }\n                }\n\n                int rank = axisRank[dir];\n                int key = (((dir * D + x) * D + y) * D + z);\n\n                if (!found ||\n                    ext < bestExt ||\n                    (ext == bestExt && rank < bestRank) ||\n                    (ext == bestExt && rank == bestRank && perp < bestPerp) ||\n                    (ext == bestExt && rank == bestRank && perp == bestPerp && key < bestKey)) {\n                    found = true;\n                    bestExt = ext;\n                    bestRank = rank;\n                    bestPerp = perp;\n                    bestKey = key;\n                    bestCells = move(cells);\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(bestCells);\n        return true;\n    }\n\n    vector<pair<int,int>> maximum_domino_pairs(const vector<char>& unused) const {\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!unused[id]) continue;\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n        vector<pair<int,int>> ret;\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) ret.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n        }\n        return ret;\n    }\n\n    Partition build_partition_spec(const OccCandidate& occCand, const PartitionSpec& spec) const {\n        Partition p;\n        p.V = occCand.V;\n        p.name = occCand.name + \":\" + spec.name;\n        p.bySize.assign(D + 1, {});\n        p.cnt.assign(D + 1, 0);\n\n        vector<char> unused = occCand.occ;\n\n        for (int phaseMask : spec.phaseMasks) {\n            for (int L : spec.lens) {\n                if (L < 3 || L > D) continue;\n                while (true) {\n                    vector<int> seg;\n                    if (!find_best_segment_mask(unused, L, phaseMask, spec.axisRank, seg)) break;\n                    for (int id : seg) unused[id] = 0;\n                    int idx = (int)p.blocks.size();\n                    p.blocks.push_back({L, seg});\n                    p.bySize[L].push_back(idx);\n                    p.cnt[L]++;\n                }\n            }\n        }\n\n        auto doms = maximum_domino_pairs(unused);\n        vector<char> used2(D * D * D, 0);\n        for (auto [a, b] : doms) {\n            if (!unused[a] || !unused[b] || used2[a] || used2[b]) continue;\n            used2[a] = used2[b] = 1;\n            int idx = (int)p.blocks.size();\n            p.blocks.push_back({2, {a, b}});\n            p.bySize[2].push_back(idx);\n            p.cnt[2]++;\n        }\n        for (int i = 0; i < D * D * D; ++i) {\n            if (used2[i]) unused[i] = 0;\n        }\n\n        for (int i = 0; i < D * D * D; ++i) {\n            if (unused[i]) {\n                int idx = (int)p.blocks.size();\n                p.blocks.push_back({1, {i}});\n                p.bySize[1].push_back(idx);\n                p.cnt[1]++;\n            }\n        }\n\n        return p;\n    }\n\n    vector<PartitionSpec> make_partition_specs() const {\n        vector<PartitionSpec> specs;\n        vector<int> desc, asc;\n        for (int L = D; L >= 3; --L) desc.push_back(L);\n        for (int L = 3; L <= D; ++L) asc.push_back(L);\n\n        auto add = [&](string name, vector<int> masks, vector<int> lens, array<int,3> rank) {\n            specs.push_back({name, masks, lens, rank});\n        };\n\n        add(\"all_zxy_desc\", {1|2|4}, desc, {1,2,0}); // z best => dir 2 rank 0, x 1, y 2\n        add(\"all_xyz_desc\", {1|2|4}, desc, {0,1,2});\n        add(\"all_zyx_asc\",  {1|2|4}, asc,  {1,2,0});\n\n        add(\"z_then_all\",   {4, 1|2|4}, desc, {1,2,0});\n        add(\"x_then_all\",   {1, 1|2|4}, desc, {0,2,1});\n        add(\"y_then_all\",   {2, 1|2|4}, desc, {2,0,1});\n\n        add(\"z_only\",       {4}, desc, {1,2,0});\n        add(\"x_only\",       {1}, desc, {0,2,1});\n        add(\"y_only\",       {2}, desc, {2,0,1});\n\n        add(\"zxy_seq\",      {4,1,2,1|2|4}, desc, {1,2,0});\n        add(\"xyz_seq\",      {1,2,4,1|2|4}, desc, {0,1,2});\n\n        return specs;\n    }\n\n    vector<Partition> build_partitions(const vector<OccCandidate>& occs) const {\n        auto specs = make_partition_specs();\n        vector<Partition> ret;\n\n        auto signature = [&](const Partition& p) {\n            string s;\n            for (int i = 1; i <= D; ++i) {\n                s += to_string(p.cnt[i]);\n                s += '#';\n            }\n            return s;\n        };\n\n        unordered_set<string> seen;\n        for (auto& occ : occs) {\n            for (auto& spec : specs) {\n                Partition p = build_partition_spec(occ, spec);\n                string sig = signature(p);\n                if (seen.insert(sig).second) ret.push_back(move(p));\n            }\n        }\n        return ret;\n    }\n\n    // ---------------- Scoring and output ----------------\n\n    long double eval_pair(const Partition& A, const Partition& B) const {\n        long double score = (long double)A.V + (long double)B.V;\n        for (int s = 1; s <= D; ++s) {\n            int k = min(A.cnt[s], B.cnt[s]);\n            score -= (long double)2 * s * k;\n            score += (long double)k / (long double)s;\n        }\n        return score;\n    }\n\n    pair<vector<int>, vector<int>> build_output_arrays(const Partition& A, const Partition& B) const {\n        vector<int> outA(D * D * D, 0), outB(D * D * D, 0);\n        int id = 1;\n\n        for (int s = D; s >= 1; --s) {\n            int k = min((int)A.bySize[s].size(), (int)B.bySize[s].size());\n            for (int i = 0; i < k; ++i) {\n                const auto& ba = A.blocks[A.bySize[s][i]];\n                const auto& bb = B.blocks[B.bySize[s][i]];\n                for (int c : ba.cells) outA[c] = id;\n                for (int c : bb.cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        for (int s = D; s >= 1; --s) {\n            int k = min((int)A.bySize[s].size(), (int)B.bySize[s].size());\n            for (int i = k; i < (int)A.bySize[s].size(); ++i) {\n                const auto& ba = A.blocks[A.bySize[s][i]];\n                for (int c : ba.cells) outA[c] = id;\n                ++id;\n            }\n            for (int i = k; i < (int)B.bySize[s].size(); ++i) {\n                const auto& bb = B.blocks[B.bySize[s][i]];\n                for (int c : bb.cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        return {outA, outB};\n    }\n\n    void solve() {\n        auto occ1 = build_occ_candidates(obj[0]);\n        auto occ2 = build_occ_candidates(obj[1]);\n\n        auto part1 = build_partitions(occ1);\n        auto part2 = build_partitions(occ2);\n\n        int bi = 0, bj = 0;\n        long double best = 1e100L;\n\n        for (int i = 0; i < (int)part1.size(); ++i) {\n            for (int j = 0; j < (int)part2.size(); ++j) {\n                long double sc = eval_pair(part1[i], part2[j]);\n                if (sc < best) {\n                    best = sc;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        auto [out1, out2] = build_output_arrays(part1[bi], part2[bj]);\n\n        int n = 0;\n        for (int v : out1) n = max(n, v);\n        for (int v : out2) n = max(n, v);\n\n        cout << n << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out1[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out2[i];\n        }\n        cout << '\\n';\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> f1(D), r1(D), f2(D), r2(D);\n    for (int i = 0; i < D; ++i) cin >> f1[i];\n    for (int i = 0; i < D; ++i) cin >> r1[i];\n    for (int i = 0; i < D; ++i) cin >> f2[i];\n    for (int i = 0; i < D; ++i) cin >> r2[i];\n\n    Solver solver(D);\n    solver.prepare_obj(0, f1, r1);\n    solver.prepare_obj(1, f2, r2);\n    solver.solve();\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }\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;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Tree {\n    vector<char> edgeOn;\n    vector<char> vertexOn;\n};\n\nstruct Solution {\n    vector<int> P;\n    vector<char> B;\n    long long S = (1LL << 62);\n    bool feasible = false;\n    double factor = 0.0;\n};\n\nstatic const long long INF64 = (1LL << 60);\nstatic const int EXACT_TERMINAL_LIMIT = 12;\n\nint N, M, K;\nvector<int> X, Y;\nvector<Edge> edges;\nvector<int> A, Br;\nvector<vector<pair<int,int>>> g;\n\nvector<vector<long long>> distSP;\nvector<vector<int>> parentV, parentE;\n\n// reqPow[v][k] = minimum integer power needed for station v to cover resident k.\n// 5001 means impossible due to P<=5000.\nvector<vector<unsigned short>> reqPow;\nvector<vector<pair<int,int>>> coverList; // (required_power, resident_id), sorted by power\n\nchrono::steady_clock::time_point g_start;\ndouble TIME_LIMIT = 1.88;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nint ceil_sqrt_ll(long long x) {\n    long long r = 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\nvoid compute_all_pairs_shortest_paths() {\n    distSP.assign(N, vector<long long>(N, INF64));\n    parentV.assign(N, vector<int>(N, -1));\n    parentE.assign(N, vector<int>(N, -1));\n\n    for (int s = 0; s < N; ++s) {\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        distSP[s][s] = 0;\n        parentV[s][s] = s;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != distSP[s][v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < distSP[s][to]) {\n                    distSP[s][to] = nd;\n                    parentV[s][to] = v;\n                    parentE[s][to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n}\n\nvoid preprocess_cover_info() {\n    reqPow.assign(N, vector<unsigned short>(K, 5001));\n    coverList.assign(N, {});\n\n    for (int v = 0; v < N; ++v) {\n        coverList[v].reserve(K);\n        for (int k = 0; k < K; ++k) {\n            long long dx = 1LL * X[v] - A[k];\n            long long dy = 1LL * Y[v] - Br[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            if (p <= 5000) {\n                reqPow[v][k] = (unsigned short)p;\n                coverList[v].push_back({p, k});\n            }\n        }\n        sort(coverList[v].begin(), coverList[v].end());\n    }\n}\n\nlong long calc_cost(const vector<int>& P, const vector<char>& Eon) {\n    long long s = 0;\n    for (int i = 0; i < N; ++i) s += 1LL * P[i] * P[i];\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nbool verify_solution(const vector<int>& P, const vector<char>& Eon) {\n    vector<char> vis(N, 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        for (auto [to, eid] : g[v]) {\n            if (!Eon[eid]) continue;\n            if (!vis[to]) {\n                vis[to] = 1;\n                q.push(to);\n            }\n        }\n    }\n\n    for (int k = 0; k < K; ++k) {\n        bool ok = false;\n        for (int v = 0; v < N; ++v) {\n            if (!vis[v]) continue;\n            if (P[v] > 0 && reqPow[v][k] <= P[v]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nvoid add_path_from_source(int s, int t, vector<char>& inTree, vector<char>& edgeOn, vector<int>& newVertices) {\n    int cur = t;\n    while (cur != s) {\n        int pe = parentE[s][cur];\n        int pv = parentV[s][cur];\n        if (pe < 0 || pv < 0) break;\n        if (!edgeOn[pe]) edgeOn[pe] = 1;\n        if (!inTree[cur]) {\n            inTree[cur] = 1;\n            newVertices.push_back(cur);\n        }\n        if (!inTree[pv]) {\n            inTree[pv] = 1;\n            newVertices.push_back(pv);\n        }\n        cur = pv;\n    }\n}\n\nvector<int> get_terminals_from_P(const vector<int>& P, vector<char>& isTerminal) {\n    isTerminal.assign(N, 0);\n    vector<int> terminals;\n    terminals.push_back(0);\n    isTerminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminals.push_back(i);\n            isTerminal[i] = 1;\n        }\n    }\n    return terminals;\n}\n\nTree finalize_tree_from_selected(const vector<char>& sel0, const vector<char>& isTerminal) {\n    vector<char> sel = sel0;\n\n    vector<vector<int>> inc(N);\n    vector<int> deg(N, 0);\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        int u = edges[e].u, v = edges[e].v;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n        deg[u]++;\n        deg[v]++;\n    }\n\n    queue<int> q;\n    for (int v = 0; v < N; ++v) {\n        if (!isTerminal[v] && deg[v] == 1) q.push(v);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (isTerminal[v] || deg[v] != 1) continue;\n\n        int remE = -1;\n        for (int e : inc[v]) if (sel[e]) {\n            remE = e;\n            break;\n        }\n        if (remE == -1) continue;\n\n        sel[remE] = 0;\n        deg[v]--;\n        int to = edges[remE].u ^ edges[remE].v ^ v;\n        deg[to]--;\n        if (!isTerminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    Tree tr;\n    tr.edgeOn = sel;\n    tr.vertexOn.assign(N, 0);\n    tr.vertexOn[0] = 1;\n    for (int i = 0; i < N; ++i) if (isTerminal[i]) tr.vertexOn[i] = 1;\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        tr.vertexOn[edges[e].u] = 1;\n        tr.vertexOn[edges[e].v] = 1;\n    }\n    return tr;\n}\n\nTree build_heuristic_tree_from_terminals(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    int T = (int)terminals.size();\n\n    if (T >= 2) {\n        vector<long long> best(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> used(T, 0);\n        best[0] = 0;\n\n        for (int it = 0; it < T; ++it) {\n            int v = -1;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                int s = terminals[par[v]];\n                int t = terminals[v];\n                int cur = t;\n                while (cur != s) {\n                    int pe = parentE[s][cur];\n                    int pv = parentV[s][cur];\n                    if (pe < 0 || pv < 0) break;\n                    unionOn[pe] = 1;\n                    cur = pv;\n                }\n            }\n\n            for (int to = 0; to < T; ++to) {\n                if (used[to]) continue;\n                long long d = distSP[terminals[v]][terminals[to]];\n                if (d < best[to]) {\n                    best[to] = d;\n                    par[to] = v;\n                }\n            }\n        }\n    }\n\n    vector<int> ids;\n    ids.reserve(M);\n    for (int e = 0; e < M; ++e) if (unionOn[e]) ids.push_back(e);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return edges[a].w < edges[b].w;\n    });\n\n    vector<char> sel(M, 0);\n    DSU dsu(N);\n    for (int e : ids) {\n        if (dsu.merge(edges[e].u, edges[e].v)) sel[e] = 1;\n    }\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_exact_tree_from_terminals(const vector<int>& terminals, const vector<char>& isTerminal) {\n    int T = (int)terminals.size();\n    int SZ = 1 << T;\n    auto IDX = [&](int mask, int v) { return mask * N + v; };\n\n    vector<long long> dp(SZ * N, INF64);\n    vector<int> kind(SZ * N, -3);    // -3 unreachable, -2 path, -1 singleton, >=0 split mask\n    vector<short> prvV(SZ * N, -1);\n    vector<short> prvE(SZ * N, -1);\n\n    for (int i = 0; i < T; ++i) {\n        int id = IDX(1 << i, terminals[i]);\n        dp[id] = 0;\n        kind[id] = -1;\n    }\n\n    for (int mask = 1; mask < SZ; ++mask) {\n        if ((mask & (mask - 1)) != 0) {\n            for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n                int oth = mask ^ sub;\n                if (sub > oth) continue;\n                for (int v = 0; v < N; ++v) {\n                    long long a = dp[IDX(sub, v)];\n                    long long b = dp[IDX(oth, v)];\n                    if (a == INF64 || b == INF64) continue;\n                    long long nv = a + b;\n                    int id = IDX(mask, v);\n                    if (nv < dp[id]) {\n                        dp[id] = nv;\n                        kind[id] = sub;\n                        prvV[id] = -1;\n                        prvE[id] = -1;\n                    }\n                }\n            }\n        }\n\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int v = 0; v < N; ++v) {\n            long long d = dp[IDX(mask, v)];\n            if (d < INF64) pq.push({d, v});\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dp[IDX(mask, v)]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                int id = IDX(mask, to);\n                if (nd < dp[id]) {\n                    dp[id] = nd;\n                    kind[id] = -2;\n                    prvV[id] = (short)v;\n                    prvE[id] = (short)eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n\n    int full = SZ - 1;\n    int bestV = 0;\n    for (int v = 1; v < N; ++v) {\n        if (dp[IDX(full, v)] < dp[IDX(full, bestV)]) bestV = v;\n    }\n\n    vector<char> sel(M, 0);\n\n    function<void(int,int)> rec = [&](int mask, int v) {\n        int id = IDX(mask, v);\n        int k = kind[id];\n        if (k == -3 || k == -1) return;\n        if (k == -2) {\n            int e = prvE[id];\n            int pv = prvV[id];\n            if (e >= 0) sel[e] = 1;\n            if (pv >= 0) rec(mask, pv);\n        } else {\n            rec(k, v);\n            rec(mask ^ k, v);\n        }\n    };\n    rec(full, bestV);\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_tree_by_P(const vector<int>& P, bool useExact) {\n    vector<char> isTerminal;\n    vector<int> terminals = get_terminals_from_P(P, isTerminal);\n    if (useExact && (int)terminals.size() <= EXACT_TERMINAL_LIMIT) {\n        return build_exact_tree_from_terminals(terminals, isTerminal);\n    } else {\n        return build_heuristic_tree_from_terminals(terminals, isTerminal);\n    }\n}\n\nvector<int> vertices_from_tree(const Tree& tr) {\n    vector<int> vs;\n    for (int i = 0; i < N; ++i) if (tr.vertexOn[i]) vs.push_back(i);\n    return vs;\n}\n\nvoid shrink_exclusive(vector<int>& P, const vector<int>& allowed) {\n    while (true) {\n        vector<int> cnt(K, 0);\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= pv) cnt[k]++;\n            }\n        }\n\n        bool changed = false;\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int oldP = P[v];\n            int need = 0;\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= oldP && cnt[k] == 1) {\n                    need = max(need, (int)reqPow[v][k]);\n                }\n            }\n            if (need < oldP) {\n                for (int k = 0; k < K; ++k) {\n                    if (reqPow[v][k] <= oldP && reqPow[v][k] > need) cnt[k]--;\n                }\n                P[v] = need;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// Greedy cover optimization on a fixed allowed set, starting from initial P.\nvector<int> greedy_cover_fixed_set(const vector<int>& allowed, vector<int> P) {\n    vector<char> ok(N, 0);\n    for (int v : allowed) ok[v] = 1;\n    for (int i = 0; i < N; ++i) if (!ok[i]) P[i] = 0;\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    for (int v : allowed) {\n        if (P[v] <= 0) continue;\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : allowed) {\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n                if (rp > P[v] && gain > 0) {\n                    long double extra = (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : allowed) {\n                    int rp = reqPow[v][k];\n                    if (rp <= 5000 && rp > P[v]) {\n                        bestV = v;\n                        bestP = rp;\n                        break;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    shrink_exclusive(P, allowed);\n    return P;\n}\n\n// Greedy repair with connection penalty from an existing connected vertex set.\n// Candidates may include vertices outside the current tree.\nvector<int> greedy_cover_with_conn(const vector<int>& candidates, vector<int> P, vector<char> inConn, double connFactor) {\n    for (int i = 0; i < N; ++i) {\n        if (P[i] > 0) inConn[i] = 1;\n    }\n\n    vector<long long> bestDist(N, INF64);\n    for (int i = 0; i < N; ++i) if (inConn[i]) {\n        for (int j = 0; j < N; ++j) {\n            if (distSP[i][j] < bestDist[j]) bestDist[j] = distSP[i][j];\n        }\n    }\n    if (bestDist[0] == INF64) {\n        for (int j = 0; j < N; ++j) bestDist[j] = distSP[0][j];\n        inConn[0] = 1;\n    }\n\n    vector<char> covered(K, 0);\n    int rem = K;\n    for (int v = 0; v < N; ++v) if (P[v] > 0) {\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : candidates) {\n            long double conn = inConn[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : candidates) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inConn[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inConn[bestV]) {\n            inConn[bestV] = 1;\n            for (int t = 0; t < N; ++t) {\n                if (distSP[bestV][t] < bestDist[t]) bestDist[t] = distSP[bestV][t];\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    vector<int> allv = candidates;\n    sort(allv.begin(), allv.end());\n    allv.erase(unique(allv.begin(), allv.end()), allv.end());\n    shrink_exclusive(P, allv);\n    return P;\n}\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> treeVertex;\n    vector<char> treeEdge;\n};\n\nInitialState initial_connected_greedy(double connFactor) {\n    vector<int> P(N, 0);\n    vector<char> inTree(N, 0), edgeOn(M, 0);\n    inTree[0] = 1;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v = 0; v < N; ++v) {\n            long double conn = inTree[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v = 0; v < N; ++v) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inTree[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inTree[bestV]) {\n            vector<int> newVertices;\n            add_path_from_source(bestFrom[bestV], bestV, inTree, edgeOn, newVertices);\n            if (newVertices.empty()) {\n                inTree[bestV] = 1;\n                newVertices.push_back(bestV);\n            }\n            for (int nv : newVertices) {\n                for (int t = 0; t < N; ++t) {\n                    if (distSP[nv][t] < bestDist[t]) {\n                        bestDist[t] = distSP[nv][t];\n                        bestFrom[t] = nv;\n                    }\n                }\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    return {P, inTree, edgeOn};\n}\n\npair<vector<int>, Tree> normalize_solution(vector<int> P, bool useExact, int rounds = 2) {\n    Tree tr;\n    for (int it = 0; it < rounds; ++it) {\n        tr = build_tree_by_P(P, false);\n        vector<int> allowed = vertices_from_tree(tr);\n        P = greedy_cover_fixed_set(allowed, P);\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n    tr = build_tree_by_P(P, useExact);\n    vector<int> allowed = vertices_from_tree(tr);\n    P = greedy_cover_fixed_set(allowed, P);\n    tr = build_tree_by_P(P, useExact);\n    return {P, tr};\n}\n\nvector<int> local_improve_drop_search(vector<int> P, double globalRepairFactor) {\n    vector<int> allVertices(N);\n    iota(allVertices.begin(), allVertices.end(), 0);\n\n    for (int round = 0; round < 2; ++round) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1);\n        P.swap(Pnorm);\n        long long curCost = calc_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> cand;\n        for (int i = 1; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            if ((deg[a] == 1) != (deg[b] == 1)) return deg[a] == 1;\n            return sa > sb;\n        });\n\n        int tryCount = min<int>((int)cand.size(), 10);\n        bool improved = false;\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n\n        vector<int> treeAllowed = vertices_from_tree(tr);\n\n        for (int idx = 0; idx < tryCount; ++idx) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int v = cand[idx];\n\n            // 1) Tree-only repair\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_fixed_set(treeAllowed, P2);\n                auto [P3, tr3] = normalize_solution(P2, false, 1);\n                long long cost3 = calc_cost(P3, tr3.edgeOn);\n                if (cost3 < bestCost && verify_solution(P3, tr3.edgeOn)) {\n                    bestCost = cost3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n\n            // 2) Global repair from current tree, allowing off-tree replacements\n            if (elapsed_sec() > TIME_LIMIT) break;\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_with_conn(allVertices, P2, tr.vertexOn, globalRepairFactor);\n                auto [P3, tr3] = normalize_solution(P2, false, 1);\n                long long cost3 = calc_cost(P3, tr3.edgeOn);\n                if (cost3 < bestCost && verify_solution(P3, tr3.edgeOn)) {\n                    bestCost = cost3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n\n    return P;\n}\n\nSolution solve_attempt(double connFactor) {\n    Solution sol;\n    sol.factor = connFactor;\n\n    InitialState init = initial_connected_greedy(connFactor);\n\n    vector<int> allowed;\n    for (int i = 0; i < N; ++i) if (init.treeVertex[i]) allowed.push_back(i);\n\n    vector<int> P0(N, 0);\n    for (int v : allowed) P0[v] = init.P[v];\n    vector<int> P = greedy_cover_fixed_set(allowed, P0);\n\n    auto [P1, tr1] = normalize_solution(P, false, 2);\n    P.swap(P1);\n\n    if (elapsed_sec() <= TIME_LIMIT) {\n        P = local_improve_drop_search(P, max(0.6, connFactor));\n    }\n\n    auto [Pfinal, trfinal] = normalize_solution(P, true, 2);\n    sol.P = Pfinal;\n    sol.B = trfinal.edgeOn;\n    sol.S = calc_cost(sol.P, sol.B);\n    sol.feasible = verify_solution(sol.P, sol.B);\n    if (!sol.feasible) sol.S = (1LL << 62);\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M >> K;\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; ++i) cin >> X[i] >> Y[i];\n\n    edges.resize(M);\n    g.assign(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, v, w};\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    A.resize(K);\n    Br.resize(K);\n    for (int i = 0; i < K; ++i) cin >> A[i] >> Br[i];\n\n    compute_all_pairs_shortest_paths();\n    preprocess_cover_info();\n\n    // Order matters because of time limit.\n    vector<double> factors = {0.8, 1.2, 0.4, 1.8, 0.0, 2.6, 0.2};\n    Solution best;\n\n    for (double f : factors) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n        Solution cur = solve_attempt(f);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    if (!best.feasible) {\n        Solution cur = solve_attempt(1.0);\n        if (cur.feasible) best = cur;\n    }\n\n    if (!best.feasible) {\n        vector<int> allv(N);\n        iota(allv.begin(), allv.end(), 0);\n        vector<int> P = greedy_cover_fixed_set(allv, vector<int>(N, 0));\n        auto [Pf, tr] = normalize_solution(P, true, 1);\n        best.P = Pf;\n        best.B = tr.edgeOn;\n        best.S = calc_cost(best.P, best.B);\n        best.feasible = verify_solution(best.P, best.B);\n    }\n\n    // One last polish on the best solution if time remains.\n    if (best.feasible && elapsed_sec() <= TIME_LIMIT) {\n        vector<int> P = local_improve_drop_search(best.P, 1.0);\n        auto [Pf, tr] = normalize_solution(P, true, 2);\n        long long S = calc_cost(Pf, tr.edgeOn);\n        if (verify_solution(Pf, tr.edgeOn) && S < best.S) {\n            best.P = Pf;\n            best.B = tr.edgeOn;\n            best.S = S;\n            best.feasible = true;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (int)best.B[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr double TL = 1.90;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Board {\n    uint16_t a[N][N];\n};\n\nstruct Plan {\n    vector<int> order;\n    int cost = 0;\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} timer_global;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n};\n\nstatic inline long long path_weight(int row, int val) {\n    // Favor pushing larger values downward, especially in upper rows.\n    return 1024LL * (N - row) + val;\n}\n\n// Bring the minimum in descendant triangle T(tx, ty) to (tx, ty).\n// Returns swap count. If ops!=nullptr, records swaps.\nstatic int apply_move(Board& b, int tx, int ty, vector<Op>* ops = nullptr) {\n    int bi = tx, bj = ty;\n    int best = b.a[tx][ty];\n\n    for (int i = tx; i < N; ++i) {\n        int L = ty;\n        int R = ty + (i - tx);\n        for (int j = L; j <= R; ++j) {\n            if ((int)b.a[i][j] < best) {\n                best = b.a[i][j];\n                bi = i;\n                bj = j;\n            }\n        }\n    }\n\n    if (bi == tx && bj == ty) return 0;\n\n    static long long memo[N][N];\n    static int seen[N][N];\n    static pair<short, short> parent_[N][N];\n    static int token = 1;\n    ++token;\n\n    auto dfs = [&](auto&& self, int i, int j) -> long long {\n        if (i == tx && j == ty) return 0;\n        if (seen[i][j] == token) return memo[i][j];\n        seen[i][j] = token;\n\n        long long best_score = LLONG_MIN / 4;\n        pair<short, short> best_parent = {-1, -1};\n\n        int d = i - tx;\n        int k = j - ty;\n\n        if (k > 0) {\n            int pi = i - 1, pj = j - 1;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n        if (k < d) {\n            int pi = i - 1, pj = j;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n\n        parent_[i][j] = best_parent;\n        memo[i][j] = best_score;\n        return best_score;\n    };\n\n    dfs(dfs, bi, bj);\n\n    int cnt = 0;\n    int i = bi, j = bj;\n    while (!(i == tx && j == ty)) {\n        auto [pi, pj] = parent_[i][j];\n        swap(b.a[i][j], b.a[pi][pj]);\n        if (ops) ops->push_back({i, j, pi, pj});\n        i = pi;\n        j = pj;\n        ++cnt;\n    }\n    return cnt;\n}\n\nstatic int simulate_order(const Board& start, int x, const vector<int>& order,\n                          Board* out_board = nullptr, vector<Op>* ops = nullptr) {\n    Board cur = start;\n    int total = 0;\n    for (int y : order) total += apply_move(cur, x, y, ops);\n    if (out_board) *out_board = cur;\n    return total;\n}\n\nstatic vector<int> make_lr_order(int m, bool rev) {\n    vector<int> ord;\n    ord.reserve(m);\n    if (!rev) for (int i = 0; i < m; ++i) ord.push_back(i);\n    else for (int i = m - 1; i >= 0; --i) ord.push_back(i);\n    return ord;\n}\n\nstatic vector<int> make_center_out_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int mid = (m - 1) / 2;\n    ord.push_back(mid);\n    for (int d = 1; (int)ord.size() < m; ++d) {\n        if (mid - d >= 0) ord.push_back(mid - d);\n        if (mid + d < m) ord.push_back(mid + d);\n    }\n    return ord;\n}\n\nstatic vector<int> make_outside_in_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int l = 0, r = m - 1;\n    while (l <= r) {\n        ord.push_back(l++);\n        if (l <= r) ord.push_back(r--);\n    }\n    return ord;\n}\n\nstatic vector<int> make_alternate_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    for (int i = 0; i < m; i += 2) ord.push_back(i);\n    for (int i = (m % 2 == 0 ? m - 1 : m - 2); i >= 1; i -= 2) ord.push_back(i);\n    return ord;\n}\n\nstatic Plan greedy_row_plan(const Board& start, int x, bool one_step_lookahead) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        int best_y = -1;\n        int best_add = INT_MAX;\n        int best_next = INT_MAX;\n        Board best_board{};\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            int nextv = 0;\n            if (one_step_lookahead && step + 1 < m) {\n                nextv = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    nextv = min(nextv, c2);\n                }\n            }\n\n            bool better = false;\n            if (add != best_add) better = (add < best_add);\n            else if (one_step_lookahead && nextv != best_next) better = (nextv < best_next);\n            else if (best_y == -1 || y < best_y) better = true;\n\n            if (better) {\n                best_y = y;\n                best_add = add;\n                best_next = nextv;\n                best_board = tmp;\n            }\n        }\n\n        ord.push_back(best_y);\n        total += best_add;\n        mask |= (1u << best_y);\n        cur = best_board;\n    }\n\n    return {ord, total};\n}\n\nstatic Plan randomized_greedy_row_plan(const Board& start, int x, XorShift64& rng) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        struct Cand {\n            int y, add, tie;\n            Board b;\n        };\n        vector<Cand> cands;\n        cands.reserve(m - step);\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            // Small extra signal for diversity / quality.\n            int tie = 0;\n            if (step + 1 < m) {\n                tie = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    tie = min(tie, c2);\n                }\n            }\n            cands.push_back({y, add, tie, tmp});\n        }\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            if (a.add != b.add) return a.add < b.add;\n            if (a.tie != b.tie) return a.tie < b.tie;\n            return a.y < b.y;\n        });\n\n        int rcl = min<int>(3, cands.size());\n        int pick = 0;\n        if (rcl == 2) {\n            pick = (rng.next_int(0, 99) < 70 ? 0 : 1);\n        } else if (rcl == 3) {\n            int v = rng.next_int(0, 99);\n            if (v < 55) pick = 0;\n            else if (v < 85) pick = 1;\n            else pick = 2;\n        }\n\n        ord.push_back(cands[pick].y);\n        total += cands[pick].add;\n        mask |= (1u << cands[pick].y);\n        cur = cands[pick].b;\n    }\n\n    return {ord, total};\n}\n\nstruct BeamNode {\n    Board b;\n    uint32_t mask;\n    int cost;\n    int parent;\n    int choice;\n};\n\nstatic int beam_width_for_row(int x) {\n    int m = x + 1;\n    if (m <= 6) return 280;\n    if (m <= 10) return 160;\n    if (m <= 14) return 90;\n    if (m <= 18) return 56;\n    if (m <= 24) return 34;\n    return 24;\n}\n\nstatic Plan beam_row_plan(const Board& start, int x) {\n    int m = x + 1;\n    if (m == 1) return {{0}, 0};\n\n    int W = beam_width_for_row(x);\n    vector<vector<BeamNode>> levels(m + 1);\n    levels[0].push_back(BeamNode{start, 0u, 0, -1, -1});\n\n    auto cmp = [](const BeamNode& A, const BeamNode& B) {\n        if (A.cost != B.cost) return A.cost < B.cost;\n        return A.mask < B.mask;\n    };\n\n    for (int depth = 0; depth < m; ++depth) {\n        vector<BeamNode> cand;\n        cand.reserve(levels[depth].size() * (m - depth));\n\n        for (int idx = 0; idx < (int)levels[depth].size(); ++idx) {\n            const BeamNode& cur = levels[depth][idx];\n            for (int y = 0; y < m; ++y) {\n                if (cur.mask & (1u << y)) continue;\n                BeamNode nxt;\n                nxt.b = cur.b;\n                int add = apply_move(nxt.b, x, y, nullptr);\n                nxt.mask = cur.mask | (1u << y);\n                nxt.cost = cur.cost + add;\n                nxt.parent = idx;\n                nxt.choice = y;\n                cand.push_back(std::move(nxt));\n            }\n        }\n\n        if ((int)cand.size() > W) {\n            nth_element(cand.begin(), cand.begin() + W, cand.end(), cmp);\n            cand.resize(W);\n        }\n        sort(cand.begin(), cand.end(), cmp);\n        levels[depth + 1] = std::move(cand);\n\n        if (timer_global.elapsed() > TL * 0.70 && m >= 20 && depth >= m / 2) break;\n    }\n\n    int last = (int)levels.size() - 1;\n    while (last > 0 && levels[last].empty()) --last;\n\n    int best_idx = 0;\n    for (int i = 1; i < (int)levels[last].size(); ++i) {\n        if (levels[last][i].cost < levels[last][best_idx].cost) best_idx = i;\n    }\n\n    vector<int> rev;\n    int idx = best_idx;\n    for (int depth = last; depth >= 1; --depth) {\n        rev.push_back(levels[depth][idx].choice);\n        idx = levels[depth][idx].parent;\n    }\n    reverse(rev.begin(), rev.end());\n\n    // If beam was cut early, finish greedily from that partial state.\n    if ((int)rev.size() < m) {\n        Board cur = start;\n        uint32_t mask = 0;\n        for (int y : rev) {\n            apply_move(cur, x, y, nullptr);\n            mask |= (1u << y);\n        }\n        while ((int)rev.size() < m) {\n            int best_y = -1, best_add = INT_MAX;\n            Board best_board{};\n            for (int y = 0; y < m; ++y) {\n                if (mask & (1u << y)) continue;\n                Board tmp = cur;\n                int add = apply_move(tmp, x, y, nullptr);\n                if (add < best_add) {\n                    best_add = add;\n                    best_y = y;\n                    best_board = tmp;\n                }\n            }\n            rev.push_back(best_y);\n            cur = best_board;\n            mask |= (1u << best_y);\n        }\n    }\n\n    int c = simulate_order(start, x, rev, nullptr, nullptr);\n    return {rev, c};\n}\n\nstatic Plan local_improve_plan(const Board& start, int x, Plan base, XorShift64& rng) {\n    int m = x + 1;\n    Plan cur = base;\n    cur.cost = simulate_order(start, x, cur.order, nullptr, nullptr);\n\n    if (m <= 14 && timer_global.elapsed() < TL * 0.78) {\n        bool improved = true;\n        while (improved && timer_global.elapsed() < TL * 0.82) {\n            improved = false;\n            Plan best = cur;\n\n            // Swap neighborhood\n            for (int i = 0; i < m; ++i) {\n                for (int j = i + 1; j < m; ++j) {\n                    vector<int> ord = cur.order;\n                    swap(ord[i], ord[j]);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            // Insertion neighborhood\n            for (int i = 0; i < m; ++i) {\n                for (int p = 0; p < m; ++p) {\n                    if (i == p) continue;\n                    vector<int> ord = cur.order;\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            if (improved) cur = best;\n        }\n    } else {\n        // Random local search for larger rows / tighter time.\n        int iters = (m <= 20 ? 180 : 120);\n        if (timer_global.elapsed() > TL * 0.75) iters /= 2;\n\n        Plan best = cur;\n        for (int t = 0; t < iters && timer_global.elapsed() < TL * 0.86; ++t) {\n            vector<int> ord = cur.order;\n            int type = rng.next_int(0, 2);\n\n            if (type == 0) {\n                int i = rng.next_int(0, m - 1);\n                int j = rng.next_int(0, m - 1);\n                if (i != j) swap(ord[i], ord[j]);\n            } else if (type == 1) {\n                int i = rng.next_int(0, m - 1);\n                int p = rng.next_int(0, m - 1);\n                if (i != p) {\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                }\n            } else {\n                int l = rng.next_int(0, m - 1);\n                int r = rng.next_int(0, m - 1);\n                if (l > r) swap(l, r);\n                reverse(ord.begin() + l, ord.begin() + r + 1);\n            }\n\n            int c = simulate_order(start, x, ord, nullptr, nullptr);\n            if (c < cur.cost || (c == cur.cost && rng.next_int(0, 1))) {\n                cur = {ord, c};\n                if (c < best.cost) best = cur;\n            }\n        }\n        if (best.cost < cur.cost) cur = best;\n    }\n\n    return cur;\n}\n\nstatic int cheap_next_proxy(const Board& b, int x) {\n    if (x >= N - 1) return 0;\n    int m = x + 1;\n    int ans = INT_MAX;\n\n    auto eval = [&](const vector<int>& ord) {\n        ans = min(ans, simulate_order(b, x, ord, nullptr, nullptr));\n    };\n\n    eval(make_lr_order(m, false));\n    eval(make_lr_order(m, true));\n    eval(make_center_out_order(m));\n    eval(make_outside_in_order(m));\n    eval(make_alternate_order(m));\n    return ans;\n}\n\nstatic vector<Plan> build_basic_candidates(const Board& b, int x, XorShift64& rng, bool with_random) {\n    int m = x + 1;\n    vector<Plan> cands;\n\n    cands.push_back(beam_row_plan(b, x));\n    cands.push_back(greedy_row_plan(b, x, false));\n    cands.push_back(greedy_row_plan(b, x, true));\n\n    auto add_order = [&](vector<int> ord) {\n        int c = simulate_order(b, x, ord, nullptr, nullptr);\n        cands.push_back({std::move(ord), c});\n    };\n\n    add_order(make_lr_order(m, false));\n    add_order(make_lr_order(m, true));\n    add_order(make_center_out_order(m));\n    add_order(make_outside_in_order(m));\n    add_order(make_alternate_order(m));\n\n    if (with_random) {\n        int rand_cnt = 0;\n        if (timer_global.elapsed() < TL * 0.45) rand_cnt = 10;\n        else if (timer_global.elapsed() < TL * 0.65) rand_cnt = 6;\n        else if (timer_global.elapsed() < TL * 0.80) rand_cnt = 3;\n\n        for (int i = 0; i < rand_cnt; ++i) {\n            cands.push_back(randomized_greedy_row_plan(b, x, rng));\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [](const Plan& a, const Plan& b) {\n        if (a.order != b.order) return a.order < b.order;\n        return a.cost < b.cost;\n    });\n    vector<Plan> uniq;\n    for (auto& p : cands) {\n        if (uniq.empty() || uniq.back().order != p.order) uniq.push_back(p);\n        else if (p.cost < uniq.back().cost) uniq.back() = p;\n    }\n    return uniq;\n}\n\n// Stronger 2-row proxy:\n// choose a row-x plan by: row cost + cheap proxy of row x+1 after it.\nstatic int future_proxy(const Board& b, int x, XorShift64& rng) {\n    if (x >= N - 1) return 0;\n\n    auto cands = build_basic_candidates(b, x, rng, false);\n\n    sort(cands.begin(), cands.end(), [](const Plan& a, const Plan& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.order < b.order;\n    });\n\n    int topk = min<int>(4, cands.size());\n    int ans = INT_MAX;\n\n    for (int i = 0; i < topk; ++i) {\n        Board after;\n        int row_cost = simulate_order(b, x, cands[i].order, &after, nullptr);\n        int val = row_cost + cheap_next_proxy(after, x + 1);\n        ans = min(ans, val);\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board board{};\n    uint64_t seed = 1469598103934665603ull;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v;\n            cin >> v;\n            board.a[x][y] = (uint16_t)v;\n            seed ^= (uint64_t)(v + 1);\n            seed *= 1099511628211ull;\n        }\n    }\n    XorShift64 rng(seed);\n\n    vector<Op> answer;\n    answer.reserve(6000);\n\n    for (int x = 0; x < N - 1; ++x) {\n        auto candidates = build_basic_candidates(board, x, rng, true);\n\n        sort(candidates.begin(), candidates.end(), [](const Plan& a, const Plan& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.order < b.order;\n        });\n\n        // Local improvement for top few.\n        vector<Plan> pool;\n        int improve_k = min<int>(4, candidates.size());\n        for (int i = 0; i < improve_k && timer_global.elapsed() < TL * 0.88; ++i) {\n            pool.push_back(local_improve_plan(board, x, candidates[i], rng));\n        }\n        for (int i = 0; i < min<int>(3, candidates.size()); ++i) pool.push_back(candidates[i]);\n\n        sort(pool.begin(), pool.end(), [](const Plan& a, const Plan& b) {\n            if (a.order != b.order) return a.order < b.order;\n            return a.cost < b.cost;\n        });\n        vector<Plan> final_cands;\n        for (auto& p : pool) {\n            if (final_cands.empty() || final_cands.back().order != p.order) final_cands.push_back(p);\n            else if (p.cost < final_cands.back().cost) final_cands.back() = p;\n        }\n\n        sort(final_cands.begin(), final_cands.end(), [](const Plan& a, const Plan& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.order < b.order;\n        });\n\n        int cand_k = min<int>(5, final_cands.size());\n        int best_idx = 0;\n        int best_eval = INT_MAX;\n        int best_row_cost = INT_MAX;\n\n        for (int i = 0; i < cand_k; ++i) {\n            Board after;\n            int row_cost = simulate_order(board, x, final_cands[i].order, &after, nullptr);\n\n            int eval = row_cost;\n            if (x + 1 < N - 1) {\n                eval += future_proxy(after, x + 1, rng);\n            }\n\n            if (eval < best_eval || (eval == best_eval && row_cost < best_row_cost)) {\n                best_eval = eval;\n                best_row_cost = row_cost;\n                best_idx = i;\n            }\n        }\n\n        simulate_order(board, x, final_cands[best_idx].order, &board, &answer);\n    }\n\n    cout << answer.size() << '\\n';\n    for (const auto& op : answer) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXV = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int lim) { return (int)(next_u64() % (uint64_t)lim); }\n};\n\nstruct Solver {\n    int D, N, M;\n    int mid, entrance;\n\n    vector<vector<int>> nbrs;\n    array<unsigned char, MAXV> obstacle{};\n    array<unsigned char, MAXV> occupied{};\n    array<int, MAXV> label_at{};\n    array<unsigned char, MAXV> used{};\n    vector<int> free_ids;\n    int current_empty_count; // includes entrance\n\n    Solver(int D_, int N_) : D(D_), N(N_) {\n        mid = (D - 1) / 2;\n        entrance = id(0, mid);\n        nbrs.assign(D * D, {});\n        label_at.fill(-1);\n        build_neighbors();\n    }\n\n    inline int id(int i, int j) const { return i * D + j; }\n    inline int row(int v) const { return v / D; }\n    inline int col(int v) const { return v % D; }\n\n    void build_neighbors() {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int v = id(i, j);\n                if (i > 0) nbrs[v].push_back(id(i - 1, j));\n                if (i + 1 < D) nbrs[v].push_back(id(i + 1, j));\n                if (j > 0) nbrs[v].push_back(id(i, j - 1));\n                if (j + 1 < D) nbrs[v].push_back(id(i, j + 1));\n            }\n        }\n    }\n\n    void finalize_init() {\n        free_ids.clear();\n        for (int v = 0; v < D * D; ++v) {\n            if (v == entrance) continue;\n            if (obstacle[v]) continue;\n            free_ids.push_back(v);\n        }\n        M = (int)free_ids.size();\n        current_empty_count = M + 1;\n    }\n\n    struct Analysis {\n        vector<int> legal;\n        array<int, MAXV> dist{};\n        array<int, MAXV> deg{};\n        array<int, MAXV> block_depth{};\n    };\n\n    Analysis analyze_empty(const array<unsigned char, MAXV>& occ) const {\n        Analysis A;\n        A.dist.fill(-1);\n        A.deg.fill(0);\n        A.block_depth.fill(0);\n\n        array<unsigned char, MAXV> active{};\n        for (int v = 0; v < D * D; ++v) {\n            active[v] = (!obstacle[v] && !occ[v]) ? 1 : 0;\n        }\n\n        for (int v = 0; v < D * D; ++v) {\n            if (!active[v]) continue;\n            int d = 0;\n            for (int to : nbrs[v]) if (active[to]) ++d;\n            A.deg[v] = d;\n        }\n\n        // BFS distance from entrance in empty graph\n        {\n            int q[MAXV];\n            int qh = 0, qt = 0;\n            q[qt++] = entrance;\n            A.dist[entrance] = 0;\n            while (qh < qt) {\n                int v = q[qh++];\n                for (int to : nbrs[v]) {\n                    if (!active[to]) continue;\n                    if (A.dist[to] != -1) continue;\n                    A.dist[to] = A.dist[v] + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        // Tarjan: articulation + biconnected components\n        array<int, MAXV> ord, low;\n        array<unsigned char, MAXV> art{};\n        ord.fill(-1);\n        low.fill(-1);\n\n        vector<pair<int,int>> estack;\n        vector<vector<int>> comps;\n        int timer = 0;\n\n        auto make_component = [&](int a, int b) {\n            vector<int> vs;\n            while (true) {\n                auto e = estack.back();\n                estack.pop_back();\n                vs.push_back(e.first);\n                vs.push_back(e.second);\n                if (e.first == a && e.second == b) break;\n            }\n            sort(vs.begin(), vs.end());\n            vs.erase(unique(vs.begin(), vs.end()), vs.end());\n            comps.push_back(move(vs));\n        };\n\n        auto dfs = [&](auto&& self, int v, int p) -> void {\n            ord[v] = low[v] = timer++;\n            int child = 0;\n            for (int to : nbrs[v]) {\n                if (!active[to]) continue;\n                if (ord[to] == -1) {\n                    ++child;\n                    estack.push_back({v, to});\n                    self(self, to, v);\n                    low[v] = min(low[v], low[to]);\n                    if (p != -1 && low[to] >= ord[v]) art[v] = 1;\n                    if (low[to] >= ord[v]) make_component(v, to);\n                } else if (to != p && ord[to] < ord[v]) {\n                    low[v] = min(low[v], ord[to]);\n                    estack.push_back({v, to});\n                }\n            }\n            if (p == -1 && child > 1) art[v] = 1;\n        };\n\n        dfs(dfs, entrance, -1);\n\n        if (!comps.empty()) {\n            vector<vector<int>> inc_comp(D * D);\n            for (int c = 0; c < (int)comps.size(); ++c) {\n                for (int v : comps[c]) inc_comp[v].push_back(c);\n            }\n\n            vector<int> art_list;\n            vector<int> art_node_idx(D * D, -1);\n            for (int v = 0; v < D * D; ++v) {\n                if (active[v] && art[v]) {\n                    art_node_idx[v] = (int)art_list.size();\n                    art_list.push_back(v);\n                }\n            }\n\n            int C = (int)comps.size();\n            int Acount = (int)art_list.size();\n            vector<vector<int>> bc(C + Acount);\n\n            for (int ai = 0; ai < Acount; ++ai) {\n                int v = art_list[ai];\n                int anode = C + ai;\n                for (int c : inc_comp[v]) {\n                    bc[anode].push_back(c);\n                    bc[c].push_back(anode);\n                }\n            }\n\n            int root_comp = -1;\n            for (int c = 0; c < C; ++c) {\n                for (int v : comps[c]) {\n                    if (v == entrance) {\n                        root_comp = c;\n                        break;\n                    }\n                }\n                if (root_comp != -1) break;\n            }\n\n            vector<int> bcdist(C + Acount, -1);\n            queue<int> q;\n            q.push(root_comp);\n            bcdist[root_comp] = 0;\n            while (!q.empty()) {\n                int x = q.front();\n                q.pop();\n                for (int y : bc[x]) {\n                    if (bcdist[y] != -1) continue;\n                    bcdist[y] = bcdist[x] + 1;\n                    q.push(y);\n                }\n            }\n\n            vector<int> comp_depth(C, 0);\n            for (int c = 0; c < C; ++c) comp_depth[c] = bcdist[c] / 2;\n\n            for (int v = 0; v < D * D; ++v) {\n                if (!active[v]) continue;\n                int bd = 0;\n                for (int c : inc_comp[v]) bd = max(bd, comp_depth[c]);\n                A.block_depth[v] = bd;\n            }\n        }\n\n        for (int v : free_ids) {\n            if (occ[v]) continue;\n            if (art[v]) continue;\n            A.legal.push_back(v);\n        }\n\n        return A;\n    }\n\n    int rank_among_remaining(const array<unsigned char, MAXV>& usd, int t) const {\n        int r = 0;\n        for (int x = 0; x < t; ++x) if (!usd[x]) ++r;\n        return r;\n    }\n\n    auto later_key(const Analysis& A, int v) const {\n        int leaf = 4 - A.deg[v];\n        int per = row(v) + abs(col(v) - mid);\n        return make_tuple(A.block_depth[v], A.dist[v], leaf, per, -v);\n    }\n\n    void sort_by_lateness(const Analysis& A, vector<int>& cells) const {\n        sort(cells.begin(), cells.end(), [&](int a, int b) {\n            return later_key(A, a) < later_key(A, b); // ascending: earlier among legal -> later among legal\n        });\n    }\n\n    int target_index(int rank, int rem, int k) const {\n        if (k <= 1) return 0;\n        if (rem <= 1) return 0;\n        long long num = 1LL * rank * (k - 1) + (rem - 1) / 2;\n        return (int)(num / (rem - 1));\n    }\n\n    vector<int> estimated_output_rank(const array<unsigned char, MAXV>& occ0, int empty_count0) const {\n        array<unsigned char, MAXV> occ = occ0;\n        int rem = empty_count0 - 1;\n        vector<int> est(D * D, -1);\n\n        for (int step = 0; step < rem; ++step) {\n            Analysis A = analyze_empty(occ);\n            vector<int> legal = A.legal;\n            sort(legal.begin(), legal.end(), [&](int a, int b) {\n                return later_key(A, a) > later_key(A, b);\n            });\n\n            int K = min(4, (int)legal.size());\n            int best = legal[0];\n            tuple<int,int,int,int,int> bestKey = {-1,-1,-1,-1,-1};\n\n            for (int i = 0; i < K; ++i) {\n                int v = legal[i];\n                array<unsigned char, MAXV> occ2 = occ;\n                occ2[v] = 1;\n                Analysis B = analyze_empty(occ2);\n                int next_legal = (int)B.legal.size();\n                int next_bd = 0;\n                for (int w : B.legal) next_bd = max(next_bd, B.block_depth[w]);\n                int leaf = 4 - A.deg[v];\n                auto key = make_tuple(A.block_depth[v], A.dist[v], next_bd, next_legal, leaf);\n                if (i == 0 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            est[best] = rem - 1 - step;\n            occ[best] = 1;\n        }\n        return est;\n    }\n\n    int smallest_accessible_remove(\n        const array<unsigned char, MAXV>& occ,\n        const array<int, MAXV>& lab\n    ) const {\n        array<unsigned char, MAXV> vis{};\n        array<unsigned char, MAXV> seen_occ{};\n        int q[MAXV];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n\n        int best = -1;\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (obstacle[to]) continue;\n                if (occ[to]) {\n                    if (!seen_occ[to]) {\n                        seen_occ[to] = 1;\n                        if (best == -1 || lab[to] < lab[best]) best = to;\n                    }\n                } else {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[qt++] = to;\n                    }\n                }\n            }\n        }\n        return best;\n    }\n\n    long long inversion_count(const vector<int>& seq) const {\n        long long inv = 0;\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            for (int j = i + 1; j < (int)seq.size(); ++j) {\n                if (seq[i] > seq[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    int cheap_policy_place(\n        const array<unsigned char, MAXV>& occ,\n        const array<unsigned char, MAXV>& usd,\n        int t,\n        int empty_count\n    ) const {\n        Analysis A = analyze_empty(occ);\n        vector<int> legal = A.legal;\n        if ((int)legal.size() == 1) return legal[0];\n\n        sort_by_lateness(A, legal);\n        int rem = empty_count - 1;\n        int r = rank_among_remaining(usd, t);\n        int idx = target_index(r, rem, (int)legal.size());\n\n        int best = legal[idx];\n        tuple<int,int,int,int,int> bestKey = {INT_MAX, 0, 0, 0, 0};\n\n        int L = max(0, idx - 1);\n        int R = min((int)legal.size() - 1, idx + 1);\n\n        for (int p = L; p <= R; ++p) {\n            int v = legal[p];\n            int flex;\n            if (rem <= 22) {\n                array<unsigned char, MAXV> occ2 = occ;\n                occ2[v] = 1;\n                Analysis B = analyze_empty(occ2);\n                flex = (int)B.legal.size();\n            } else {\n                flex = A.deg[v];\n            }\n            int per = row(v) + abs(col(v) - mid);\n            auto key = make_tuple(abs(p - idx), -flex, A.block_depth[v], A.dist[v], per);\n            if (p == L || key < bestKey) {\n                best = v;\n                bestKey = key;\n            }\n        }\n\n        return best;\n    }\n\n    long long evaluate_candidate(\n        int place_v,\n        int current_t,\n        const vector<vector<int>>& perms\n    ) const {\n        long long total = 0;\n\n        for (const auto& perm : perms) {\n            array<unsigned char, MAXV> occ = occupied;\n            array<int, MAXV> lab = label_at;\n            array<unsigned char, MAXV> usd = used;\n            int empty_count = current_empty_count;\n\n            occ[place_v] = 1;\n            lab[place_v] = current_t;\n            usd[current_t] = 1;\n            --empty_count;\n\n            for (int t : perm) {\n                int v = cheap_policy_place(occ, usd, t, empty_count);\n                occ[v] = 1;\n                lab[v] = t;\n                usd[t] = 1;\n                --empty_count;\n            }\n\n            vector<int> seq;\n            seq.reserve(M);\n            for (int iter = 0; iter < M; ++iter) {\n                int v = smallest_accessible_remove(occ, lab);\n                seq.push_back(lab[v]);\n                occ[v] = 0;\n            }\n            total += inversion_count(seq);\n        }\n\n        return total;\n    }\n\n    int count_legal_after_place(int v) const {\n        array<unsigned char, MAXV> occ2 = occupied;\n        occ2[v] = 1;\n        Analysis B = analyze_empty(occ2);\n        return (int)B.legal.size();\n    }\n\n    int choose_place(int t, int step_idx) const {\n        int rem = current_empty_count - 1;\n        Analysis A = analyze_empty(occupied);\n        vector<int> legal_sorted = A.legal;\n        sort_by_lateness(A, legal_sorted);\n\n        int r = rank_among_remaining(used, t);\n        int idx = target_index(r, rem, (int)legal_sorted.size());\n\n        array<int, MAXV> pos;\n        pos.fill(-1);\n        for (int i = 0; i < (int)legal_sorted.size(); ++i) pos[legal_sorted[i]] = i;\n\n        vector<int> est = estimated_output_rank(occupied, current_empty_count);\n\n        vector<int> cand;\n        array<unsigned char, MAXV> in_cand{};\n        auto add_cand = [&](int v) {\n            if (v < 0) return;\n            if (!in_cand[v]) {\n                in_cand[v] = 1;\n                cand.push_back(v);\n            }\n        };\n\n        for (int d = -2; d <= 2; ++d) {\n            int p = idx + d;\n            if (0 <= p && p < (int)legal_sorted.size()) add_cand(legal_sorted[p]);\n        }\n        add_cand(legal_sorted.front());\n        add_cand(legal_sorted.back());\n\n        int best_est = -1;\n        tuple<long long,int,int,int,int> bestEstKey;\n        for (int v : A.legal) {\n            long long diff = llabs((long long)est[v] - r);\n            int later_penalty = (est[v] > r) ? 1 : 0;\n            int pdiff = abs(pos[v] - idx);\n            auto key = make_tuple(diff, later_penalty, pdiff, A.block_depth[v], A.dist[v]);\n            if (best_est == -1 || key < bestEstKey) {\n                best_est = v;\n                bestEstKey = key;\n            }\n        }\n        add_cand(best_est);\n\n        // Base tie-break key\n        unordered_map<int, tuple<long long,int,int,int,int,int>> baseKey;\n        for (int v : cand) {\n            long long diff = llabs((long long)est[v] - r);\n            int later_penalty = (est[v] > r) ? 1 : 0;\n            int pdiff = abs(pos[v] - idx);\n            int next_legal = count_legal_after_place(v);\n            int per = row(v) + abs(col(v) - mid);\n            baseKey[v] = make_tuple(diff, later_penalty, pdiff, -next_legal, A.block_depth[v], per);\n        }\n\n        // Sample future permutations (common random numbers for all candidates)\n        vector<int> rem_labels;\n        rem_labels.reserve(rem - 1);\n        for (int x = 0; x < M; ++x) {\n            if (!used[x] && x != t) rem_labels.push_back(x);\n        }\n\n        int samples;\n        if (rem >= 55) samples = 2;\n        else if (rem >= 32) samples = 3;\n        else if (rem >= 16) samples = 4;\n        else samples = 5;\n\n        uint64_t seed = 1469598103934665603ull;\n        seed ^= (uint64_t)step_idx * 1099511628211ull;\n        seed ^= (uint64_t)(t + 1) * 1000003ull;\n        for (int v = 0; v < D * D; ++v) {\n            if (obstacle[v]) seed ^= (uint64_t)(v + 7) * 911382323ull;\n        }\n        XorShift64 rng(seed);\n\n        vector<vector<int>> perms;\n        perms.reserve(samples);\n        for (int s = 0; s < samples; ++s) {\n            vector<int> p = rem_labels;\n            for (int i = (int)p.size() - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(p[i], p[j]);\n            }\n            perms.push_back(move(p));\n        }\n\n        int best = cand[0];\n        long long bestVal = -1;\n        auto bestBase = baseKey[best];\n\n        for (int v : cand) {\n            long long val = evaluate_candidate(v, t, perms);\n            if (bestVal == -1 || val < bestVal || (val == bestVal && baseKey[v] < bestBase)) {\n                best = v;\n                bestVal = val;\n                bestBase = baseKey[v];\n            }\n        }\n\n        return best;\n    }\n\n    int choose_remove_actual() const {\n        return smallest_accessible_remove(occupied, label_at);\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    Solver solver(D, N);\n\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        solver.obstacle[solver.id(r, c)] = 1;\n    }\n    solver.finalize_init();\n\n    for (int step = 0; step < solver.M; ++step) {\n        int t;\n        cin >> t;\n\n        int v = solver.choose_place(t, step);\n\n        solver.occupied[v] = 1;\n        solver.label_at[v] = t;\n        solver.used[t] = 1;\n        --solver.current_empty_count;\n\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n' << flush;\n    }\n\n    for (int k = 0; k < solver.M; ++k) {\n        int v = solver.choose_remove_actual();\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n';\n        solver.occupied[v] = 0;\n    }\n    cout << flush;\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXC = 100;\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 DeltaPack {\n    int u[16], v[16], d[16];\n    int sz = 0;\n\n    void clear() { sz = 0; }\n\n    void add(int a, int b, int val) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < sz; i++) {\n            if (u[i] == a && v[i] == b) {\n                d[i] += val;\n                return;\n            }\n        }\n        u[sz] = a;\n        v[sz] = b;\n        d[sz] = val;\n        sz++;\n    }\n};\n\nstruct Solver {\n    int n, m;\n    int orig[MAXN][MAXN];\n    bool target[MAXC + 1][MAXC + 1]{};\n\n    int g[MAXN][MAXN];\n    int bestg[MAXN][MAXN];\n\n    int area[MAXC + 1]{};\n    int adjcnt[MAXC + 1][MAXC + 1]{};\n\n    int bestZero = 0;\n\n    mt19937 rng;\n\n    static constexpr int DX[4] = {-1, 1, 0, 0};\n    static constexpr int DY[4] = {0, 0, -1, 1};\n\n    Solver() {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < n && 0 <= y && y < n;\n    }\n\n    void build_adj_from_board(int board[MAXN][MAXN], int cnt[MAXC + 1][MAXC + 1]) {\n        for (int i = 0; i <= m; i++) for (int j = 0; j <= m; j++) cnt[i][j] = 0;\n\n        auto add_pair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            cnt[a][b]++;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int c = board[i][j];\n                if (i == 0) add_pair(c, 0);\n                if (j == 0) add_pair(c, 0);\n                if (i + 1 < n) add_pair(c, board[i + 1][j]);\n                else add_pair(c, 0);\n                if (j + 1 < n) add_pair(c, board[i][j + 1]);\n                else add_pair(c, 0);\n            }\n        }\n    }\n\n    void init_target() {\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(orig, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = 0; j <= m; j++) target[i][j] = false;\n        }\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                target[i][j] = target[j][i] = (cnt[i][j] > 0);\n            }\n        }\n    }\n\n    void reset_state() {\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) g[i][j] = orig[i][j];\n        for (int c = 0; c <= m; c++) area[c] = 0;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) area[g[i][j]]++;\n        build_adj_from_board(g, adjcnt);\n        bestZero = area[0];\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = g[i][j];\n    }\n\n    bool can_remove_color_cell(int x, int y) {\n        int c = g[x][y];\n        if (c == 0) return false;\n        if (area[c] <= 1) return false;\n\n        pair<int,int> same[4];\n        int k = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == c) same[k++] = {nx, ny};\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        static int vis[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        q.push(same[0]);\n        vis[same[0].first][same[0].second] = stamp;\n        int cnt = 0;\n\n        while (!q.empty()) {\n            auto [cx, cy] = q.front();\n            q.pop();\n            cnt++;\n            if (cnt == area[c] - 1) return true;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = cx + DX[dir], ny = cy + DY[dir];\n                if (!inside(nx, ny)) continue;\n                if (nx == x && ny == y) continue;\n                if (g[nx][ny] != c) continue;\n                if (vis[nx][ny] == stamp) continue;\n                vis[nx][ny] = stamp;\n                q.push({nx, ny});\n            }\n        }\n        return cnt == area[c] - 1;\n    }\n\n    bool can_attach_zero(int x, int y) const {\n        if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return true;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == 0) return true;\n        }\n        return false;\n    }\n\n    bool check_move(int x, int y, int t, int &deltaPerim, DeltaPack &pack) {\n        int c = g[x][y];\n        if (c == 0 || c == t) return false;\n\n        if (t == 0) {\n            if (!can_attach_zero(x, y)) return false;\n        } else {\n            bool touch = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (inside(nx, ny) && g[nx][ny] == t) {\n                    touch = true;\n                    break;\n                }\n            }\n            if (!touch) return false;\n        }\n\n        pack.clear();\n        deltaPerim = 0;\n\n        auto process_side = [&](int other) {\n            deltaPerim += (t != other) - (c != other);\n            pack.add(c, other, -1);\n            pack.add(t, other, +1);\n        };\n\n        if (x > 0) process_side(g[x - 1][y]);\n        else process_side(0);\n        if (x + 1 < n) process_side(g[x + 1][y]);\n        else process_side(0);\n        if (y > 0) process_side(g[x][y - 1]);\n        else process_side(0);\n        if (y + 1 < n) process_side(g[x][y + 1]);\n        else process_side(0);\n\n        for (int i = 0; i < pack.sz; i++) {\n            int a = pack.u[i], b = pack.v[i];\n            int after = adjcnt[a][b] + pack.d[i];\n            if ((after > 0) != target[a][b]) return false;\n        }\n        return true;\n    }\n\n    void apply_move(int x, int y, int t, const DeltaPack &pack) {\n        int c = g[x][y];\n        area[c]--;\n        area[t]++;\n        g[x][y] = t;\n        for (int i = 0; i < pack.sz; i++) {\n            adjcnt[pack.u[i]][pack.v[i]] += pack.d[i];\n        }\n        if (area[0] > bestZero) {\n            bestZero = area[0];\n            for (int r = 0; r < n; r++) for (int c2 = 0; c2 < n; c2++) bestg[r][c2] = g[r][c2];\n        }\n    }\n\n    bool try_zero_move(int x, int y) {\n        if (!inside(x, y)) return false;\n        if (g[x][y] == 0) return false;\n        if (!can_remove_color_cell(x, y)) return false;\n        int dp;\n        DeltaPack pack;\n        if (!check_move(x, y, 0, dp, pack)) return false;\n        apply_move(x, y, 0, pack);\n        return true;\n    }\n\n    void harvest_local(const vector<pair<int,int>> &seeds) {\n        static int seen[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        auto push = [&](int x, int y) {\n            if (!inside(x, y)) return;\n            if (seen[x][y] == stamp) return;\n            seen[x][y] = stamp;\n            q.push({x, y});\n        };\n\n        for (auto [x, y] : seeds) {\n            push(x, y);\n            for (int dir = 0; dir < 4; dir++) push(x + DX[dir], y + DY[dir]);\n        }\n\n        while (!q.empty()) {\n            auto [x, y] = q.front();\n            q.pop();\n            if (!inside(x, y)) continue;\n            if (g[x][y] == 0) continue;\n            if (try_zero_move(x, y)) {\n                push(x, y);\n                for (int dir = 0; dir < 4; dir++) {\n                    push(x + DX[dir], y + DY[dir]);\n                    push(x + 2 * DX[dir], y + 2 * DY[dir]);\n                }\n            }\n        }\n    }\n\n    int strict_sweep_once() {\n        vector<int> ord(n * n);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        int changes = 0;\n\n        for (int id : ord) {\n            int x = id / n, y = id % n;\n            if (g[x][y] == 0) continue;\n\n            if (try_zero_move(x, y)) {\n                changes++;\n                continue;\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int bestT = -1, bestDP = 100;\n            DeltaPack bestPack;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == g[x][y] || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                if (dp < bestDP) {\n                    bestDP = dp;\n                    bestT = t;\n                    bestPack = pack;\n                }\n            }\n\n            if (bestT != -1) {\n                bool accept = false;\n                if (bestDP < 0) accept = true;\n                else if (bestDP == 0 && (rng() & 3) == 0) accept = true;\n\n                if (accept) {\n                    apply_move(x, y, bestT, bestPack);\n                    harvest_local({{x, y}});\n                    changes++;\n                }\n            }\n        }\n\n        return changes;\n    }\n\n    void run_search(double limit_sec, const Timer &timer) {\n        reset_state();\n\n        while (timer.elapsed() < limit_sec * 0.25) {\n            int ch = strict_sweep_once();\n            if (ch == 0) break;\n        }\n\n        uniform_int_distribution<int> cellDist(0, n * n - 1);\n\n        long long iter = 0;\n        long long lastImproveIter = 0;\n        int localBest = bestZero;\n\n        while (timer.elapsed() < limit_sec) {\n            iter++;\n\n            if ((iter % 3000) == 0) {\n                int ch = strict_sweep_once();\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n                if (ch == 0 && iter - lastImproveIter > 20000) {\n                    // Mild reshuffle via another sweep; no reset, just continue.\n                    strict_sweep_once();\n                    lastImproveIter = iter;\n                }\n            }\n\n            int id = cellDist(rng);\n            int x = id / n, y = id % n;\n            int c = g[x][y];\n            if (c == 0) continue;\n\n            if ((iter & 7) == 0) {\n                if (try_zero_move(x, y)) {\n                    harvest_local({{x, y}});\n                    if (bestZero > localBest) {\n                        localBest = bestZero;\n                        lastImproveIter = iter;\n                    }\n                    continue;\n                }\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int candT[4], candDP[4], candK = 0;\n            DeltaPack candPack[4];\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == c || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                candT[candK] = t;\n                candDP[candK] = dp;\n                candPack[candK] = pack;\n                candK++;\n            }\n\n            if (candK == 0) continue;\n\n            int pick = 0;\n            if (candK >= 2 && (rng() % 100) < 35) {\n                pick = rng() % candK;\n            } else {\n                for (int i = 1; i < candK; i++) {\n                    if (candDP[i] < candDP[pick]) pick = i;\n                }\n            }\n\n            int dp = candDP[pick];\n            double t01 = timer.elapsed() / limit_sec;\n            double temp = 1.8 * (1.0 - t01) + 0.03 * t01;\n\n            bool accept = false;\n            if (dp <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-double(dp) / temp);\n                uint32_t rv = rng();\n                double u = (rv + 0.5) * (1.0 / 4294967296.0);\n                if (u < prob) accept = true;\n            }\n\n            if (accept) {\n                apply_move(x, y, candT[pick], candPack[pick]);\n                harvest_local({{x, y}});\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n            }\n        }\n    }\n\n    bool full_validate(int board[MAXN][MAXN]) {\n        int cntArea[MAXC + 1] = {};\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cntArea[board[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cntArea[c] == 0) return false;\n\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(board, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                bool cur = cnt[i][j] > 0;\n                if (cur != target[i][j]) return false;\n            }\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // Positive colors connectivity\n        vector<vector<int>> vis(n, vector<int>(n, -1));\n        for (int c = 1; c <= m; c++) {\n            pair<int,int> st = {-1, -1};\n            for (int i = 0; i < n && st.first == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (board[i][j] == c) {\n                        st = {i, j};\n                        break;\n                    }\n                }\n            }\n            if (st.first == -1) return false;\n\n            queue<pair<int,int>> q;\n            q.push(st);\n            vis[st.first][st.second] = c;\n            int got = 0;\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != c || vis[nx][ny] == c) continue;\n                    vis[nx][ny] = c;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[c]) return false;\n        }\n\n        // Zero connectivity through outside = every zero cell must connect to boundary zero.\n        if (cntArea[0] > 0) {\n            vector<vector<int>> zvis(n, vector<int>(n, 0));\n            queue<pair<int,int>> q;\n            int got = 0;\n\n            for (int i = 0; i < n; i++) {\n                for (int j : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n            for (int j = 0; j < n; j++) {\n                for (int i : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != 0 || zvis[nx][ny]) continue;\n                    zvis[nx][ny] = 1;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[0]) return false;\n        }\n\n        return true;\n    }\n\n    void solve() {\n        cin >> n >> m;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) cin >> orig[i][j];\n        }\n\n        init_target();\n\n        Timer timer;\n        const double TL = 1.92;\n\n        run_search(TL, timer);\n\n        if (!full_validate(bestg)) {\n            for (int i = 0; i < n; i++) {\n                for (int j = 0; j < n; j++) {\n                    cout << orig[i][j] << (j + 1 == n ? '\\n' : ' ');\n                }\n            }\n            return;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                cout << bestg[i][j] << (j + 1 == n ? '\\n' : ' ');\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Bin {\n    vector<int> items;\n    long double est_load = 0;\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int lgD = 0;\n\n    vector<int> insc;                     // insertion sort cost upper bound\n    vector<long double> H, est_pos, pref; // expected rank weights\n    vector<long double> est_item;         // estimated weight of each item\n    vector<vector<signed char>> cache;    // 2 unknown, -1 <, 0 =, 1 >\n    vector<uint64_t> keyv;\n\n    static int ceil_log2_int(int x) {\n        int k = 0, p = 1;\n        while (p < x) p <<= 1, ++k;\n        return k;\n    }\n\n    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    int remain() const { return Q - used; }\n\n    int ask_raw(const vector<int>& L, const vector<int>& R) {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        cin >> s;\n        ++used;\n        if (s == \"<\") return -1;\n        if (s == \">\") return 1;\n        return 0;\n    }\n\n    int cmp_item(int a, int b) {\n        if (cache[a][b] != 2) return cache[a][b];\n        vector<int> L{a}, R{b};\n        int c = ask_raw(L, R);\n        cache[a][b] = (signed char)c;\n        cache[b][a] = (signed char)(-c);\n        return c;\n    }\n\n    int cmp_sets(const vector<int>& A, const vector<int>& B) {\n        if (A.size() == 1 && B.size() == 1) return cmp_item(A[0], B[0]);\n        return ask_raw(A, B);\n    }\n\n    long double pref_val(int k) const {\n        if (k < 0) return 0;\n        if (k > N) k = N;\n        return pref[k];\n    }\n\n    vector<int> exact_sort_items(const vector<int>& items) {\n        // descending: heavier first\n        vector<int> sorted;\n        sorted.reserve(items.size());\n        for (int x : items) {\n            int l = 0, r = (int)sorted.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = cmp_item(x, sorted[m]);\n                if (c > 0) r = m;\n                else l = m + 1;\n            }\n            sorted.insert(sorted.begin() + l, x);\n        }\n        return sorted;\n    }\n\n    vector<int> swiss_order(int rounds) {\n        vector<int> score(N, 0);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return keyv[a] < keyv[b];\n        });\n\n        for (int r = 0; r < rounds; ++r) {\n            uint64_t salt = splitmix64(123456789ULL + r * 1000003ULL + N * 911ULL + D * 3571ULL + Q);\n\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (score[a] != score[b]) return score[a] > score[b];\n                uint64_t ka = keyv[a] ^ salt;\n                uint64_t kb = keyv[b] ^ salt;\n                return ka < kb;\n            });\n\n            for (int i = 0; i + 1 < N; i += 2) {\n                int a = ord[i], b = ord[i + 1];\n                int c = cmp_item(a, b);\n                if (c > 0) {\n                    ++score[a];\n                    --score[b];\n                } else if (c < 0) {\n                    ++score[b];\n                    --score[a];\n                }\n            }\n        }\n\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return keyv[a] < keyv[b];\n        });\n        return ord;\n    }\n\n    pair<int, long double> choose_best_M(int rem, int rounds_factor) {\n        // Utility:\n        // - exact prefix M matters a lot\n        // - actual insertion prefix K matters too\n        long double rel = 0.40L + 0.12L * rounds_factor;\n        int bestM = 0;\n        long double bestU = -1e100L;\n\n        for (int M = 0; M <= N; ++M) {\n            if (insc[M] > rem) break;\n            int K = 0;\n            if (M >= D) {\n                K = min(M, D + (rem - insc[M]) / max(1, lgD));\n            }\n            long double u = rel * pref_val(M) + 1.00L * pref_val(K);\n            if (u > bestU) {\n                bestU = u;\n                bestM = M;\n            }\n        }\n        return {bestM, bestU};\n    }\n\n    void insert_bin_sorted_actual(vector<Bin>& bins, Bin cur) {\n        int l = 0, r = (int)bins.size();\n        while (l < r) {\n            int m = (l + r) >> 1;\n            int c = cmp_sets(cur.items, bins[m].items); // cur ? bins[m]\n            if (c <= 0) r = m;\n            else l = m + 1;\n        }\n        bins.insert(bins.begin() + l, std::move(cur));\n    }\n\n    vector<Bin> actual_assign_prefix(const vector<int>& order, int K) {\n        // order[0..K) is exact descending\n        vector<Bin> bins;\n        bins.reserve(D);\n        if (K < D) return bins;\n\n        // initialize as ascending actual weight\n        for (int j = 0; j < D; ++j) {\n            Bin b;\n            int item = order[D - 1 - j];\n            b.items.push_back(item);\n            b.est_load = est_item[item];\n            bins.push_back(std::move(b));\n        }\n\n        for (int p = D; p < K; ++p) {\n            Bin cur = std::move(bins.front());\n            bins.erase(bins.begin());\n\n            int item = order[p];\n            cur.items.push_back(item);\n            cur.est_load += est_item[item];\n\n            insert_bin_sorted_actual(bins, std::move(cur));\n        }\n        return bins;\n    }\n\n    vector<Bin> estimated_assign_rest(const vector<int>& order, int start, vector<Bin> bins) {\n        if (bins.empty()) bins.assign(D, Bin());\n\n        for (int p = start; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_item[item];\n        }\n        return bins;\n    }\n\n    static void erase_one(vector<int>& v, int x) {\n        for (int i = 0; i < (int)v.size(); ++i) {\n            if (v[i] == x) {\n                v.erase(v.begin() + i);\n                return;\n            }\n        }\n    }\n\n    void local_improve(vector<Bin>& bins, const vector<char>& fixed) {\n        for (int iter = 0; iter < 350; ++iter) {\n            int hi = 0, lo = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load > bins[hi].est_load) hi = j;\n                if (bins[j].est_load < bins[lo].est_load) lo = j;\n            }\n            if (hi == lo) break;\n\n            long double A = bins[hi].est_load;\n            long double B = bins[lo].est_load;\n            long double best_diff = fabsl(A - B);\n\n            int type = 0; // 1 move, 2 swap\n            int bx = -1, by = -1;\n\n            if ((int)bins[hi].items.size() > 1) {\n                for (int x : bins[hi].items) {\n                    if (fixed[x]) continue;\n                    long double w = est_item[x];\n                    long double nd = fabsl((A - w) - (B + w));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 1;\n                        bx = x;\n                        by = -1;\n                    }\n                }\n            }\n\n            for (int x : bins[hi].items) {\n                if (fixed[x]) continue;\n                long double wx = est_item[x];\n                for (int y : bins[lo].items) {\n                    if (fixed[y]) continue;\n                    long double wy = est_item[y];\n                    long double nd = fabsl((A - wx + wy) - (B - wy + wx));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 2;\n                        bx = x;\n                        by = y;\n                    }\n                }\n            }\n\n            if (type == 0) break;\n\n            if (type == 1) {\n                erase_one(bins[hi].items, bx);\n                bins[lo].items.push_back(bx);\n                long double w = est_item[bx];\n                bins[hi].est_load -= w;\n                bins[lo].est_load += w;\n            } else {\n                erase_one(bins[hi].items, bx);\n                erase_one(bins[lo].items, by);\n                bins[hi].items.push_back(by);\n                bins[lo].items.push_back(bx);\n                long double wx = est_item[bx];\n                long double wy = est_item[by];\n                bins[hi].est_load += wy - wx;\n                bins[lo].est_load += wx - wy;\n            }\n        }\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        lgD = ceil_log2_int(D);\n\n        insc.assign(N + 1, 0);\n        for (int k = 2; k <= N; ++k) insc[k] = insc[k - 1] + ceil_log2_int(k);\n\n        H.assign(N + 1, 0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0L / i;\n\n        est_pos.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_pos[p] = H[N] - H[p];\n\n        pref.assign(N + 1, 0);\n        for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + est_pos[i];\n\n        cache.assign(N, vector<signed char>(N, 2));\n        for (int i = 0; i < N; ++i) cache[i][i] = 0;\n\n        keyv.resize(N);\n        for (int i = 0; i < N; ++i) {\n            keyv[i] = splitmix64((uint64_t)(i + 1) * 1234567ULL + N * 10007ULL + D * 1000003ULL + Q * 998244353ULL);\n        }\n\n        // Choose global strategy:\n        // - exact-all if very attractive\n        // - otherwise swiss rounds + exact prefix\n        bool use_exact_all = false;\n        int best_rounds = 0;\n        long double best_util = -1e100L;\n\n        if (insc[N] <= Q) {\n            int K = min(N, D + (Q - insc[N]) / max(1, lgD));\n            long double util = 1.10L * pref_val(N) + 1.00L * pref_val(K);\n            best_util = util;\n            use_exact_all = true;\n        }\n\n        int round_cost = N / 2;\n        int Rmax = (round_cost == 0 ? 0 : min(6, Q / round_cost));\n        for (int R = 1; R <= Rmax; ++R) {\n            int rem = Q - R * round_cost;\n            if (rem < 0) continue;\n            auto [m, u0] = choose_best_M(rem, R);\n            long double u = u0 + 0.01L * R * pref_val(N);\n            if (u > best_util) {\n                best_util = u;\n                use_exact_all = false;\n                best_rounds = R;\n            }\n        }\n\n        vector<int> order;\n        int exact_prefix_len = 0;\n\n        if (use_exact_all) {\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            order = exact_sort_items(all);\n            exact_prefix_len = N;\n        } else {\n            vector<int> coarse = swiss_order(best_rounds);\n\n            int rem = remain();\n            auto [M, _u] = choose_best_M(rem, best_rounds);\n\n            vector<int> prefix(coarse.begin(), coarse.begin() + M);\n            vector<int> exact_prefix = exact_sort_items(prefix);\n\n            order.reserve(N);\n            for (int x : exact_prefix) order.push_back(x);\n            for (int i = M; i < N; ++i) order.push_back(coarse[i]);\n\n            exact_prefix_len = M;\n        }\n\n        est_item.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_item[order[p]] = est_pos[p];\n\n        int K_actual = 0;\n        if (exact_prefix_len >= D) {\n            K_actual = min(exact_prefix_len, D + remain() / max(1, lgD));\n        }\n\n        vector<char> fixed(N, 0);\n        for (int p = 0; p < K_actual; ++p) fixed[order[p]] = 1;\n\n        vector<Bin> bins;\n        if (K_actual >= D) {\n            bins = actual_assign_prefix(order, K_actual);\n            bins = estimated_assign_rest(order, K_actual, std::move(bins));\n        } else {\n            bins = estimated_assign_rest(order, 0, {});\n        }\n\n        local_improve(bins, fixed);\n\n        while (used < Q) {\n            vector<int> L{0}, R{1};\n            ask_raw(L, R);\n        }\n\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b].items) ans[x] = b;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Policy {\n    int max_chunks = 4;\n    int shortlist = 20;\n    int boundary_B = 7;\n\n    int move_pen = 14;\n    int seg_inv_w = 3;\n    int seg_adj_w = 9;\n\n    int dest_inv_w = 7;\n    int fit_w = 3;\n    int top_w = 2;\n    int size_w = 1;\n    int empty_bonus = 20;\n    int bad_fit_base = 24;\n    int bad_fit_mul = 3;\n\n    int final_move_w = 340;\n    int final_assign_w = 1;\n    int final_global_w = 6;\n    int final_future_w = 28;\n    int final_removed_bonus = 420;\n    int future_depth = 4;\n\n    int gen_pen1 = 4;\n    int gen_pen2 = 7;\n    int gen_pen3 = 9;\n    bool use_dec_runs = true;\n};\n\nstruct Result {\n    long long energy;\n    vector<pair<int,int>> ops;\n};\n\nstruct Simulator {\n    int n, m;\n    vector<vector<int>> init_st;\n\n    Simulator(int n_, int m_, const vector<vector<int>>& st_) : n(n_), m(m_), init_st(st_) {}\n\n    static 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    int urgency(int x, int cur) const {\n        int d = x - cur;\n        if (d <= 10) return 5;\n        if (d <= 20) return 4;\n        if (d <= 40) return 3;\n        if (d <= 80) return 2;\n        return 1;\n    }\n\n    void remove_possible(vector<vector<int>>& st, vector<pair<int,int>>& ops, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ops.push_back({cur, 0});\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    void remove_possible_state_only(vector<vector<int>>& st, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    pair<int,int> find_box(const vector<vector<int>>& st, int v) const {\n        for (int i = 0; i < m; 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    long long cross_inv_cost(const vector<int>& dst, const vector<int>& chunk, int cur) const {\n        long long c = 0;\n        for (int x : dst) {\n            int w = urgency(x, cur);\n            for (int y : chunk) {\n                if (x < y) c += w;\n            }\n        }\n        return c;\n    }\n\n    vector<pair<int,int>> decode_mask(int t, uint32_t mask) const {\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if ((mask >> i) & 1U) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n        return segs;\n    }\n\n    uint32_t encode_segs(const vector<pair<int,int>>& segs) const {\n        uint32_t mask = 0;\n        for (int i = 0; i + 1 < (int)segs.size(); i++) {\n            mask |= (1U << segs[i].second);\n        }\n        return mask;\n    }\n\n    uint32_t partition_by_metric(const vector<vector<long long>>& metric, int t, int max_chunks, int pen) const {\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> dp(max_chunks + 1, vector<long long>(t + 1, INF));\n        vector<vector<int>> prv(max_chunks + 1, vector<int>(t + 1, -1));\n        dp[0][0] = 0;\n        for (int k = 1; k <= max_chunks; k++) {\n            for (int i = 1; i <= t; i++) {\n                for (int l = 0; l < i; l++) {\n                    if (dp[k - 1][l] == INF) continue;\n                    long long cand = dp[k - 1][l] + metric[l][i - 1] + pen;\n                    if (cand < dp[k][i]) {\n                        dp[k][i] = cand;\n                        prv[k][i] = l;\n                    }\n                }\n            }\n        }\n        int best_k = 1;\n        long long best = dp[1][t];\n        for (int k = 2; k <= max_chunks; k++) {\n            if (dp[k][t] < best) {\n                best = dp[k][t];\n                best_k = k;\n            }\n        }\n        vector<pair<int,int>> rev;\n        int i = t, k = best_k;\n        while (k > 0) {\n            int l = prv[k][i];\n            rev.push_back({l, i - 1});\n            i = l;\n            --k;\n        }\n        reverse(rev.begin(), rev.end());\n        return encode_segs(rev);\n    }\n\n    uint32_t decreasing_runs_mask(const vector<int>& b, int max_chunks,\n                                  const vector<vector<long long>>& merge_metric) const {\n        int t = (int)b.size();\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if (b[i] < b[i + 1]) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n\n        while ((int)segs.size() > max_chunks) {\n            long long best_add = (1LL << 60);\n            int best_i = -1;\n            for (int i = 0; i + 1 < (int)segs.size(); i++) {\n                int l0 = segs[i].first;\n                int r0 = segs[i].second;\n                int l1 = segs[i + 1].first;\n                int r1 = segs[i + 1].second;\n                long long add = merge_metric[l0][r1] - merge_metric[l0][r0] - merge_metric[l1][r1];\n                if (add < best_add) {\n                    best_add = add;\n                    best_i = i;\n                }\n            }\n            segs[best_i].second = segs[best_i + 1].second;\n            segs.erase(segs.begin() + best_i + 1);\n        }\n        return encode_segs(segs);\n    }\n\n    bool assign_unique_destinations(\n        const vector<vector<int>>& st,\n        int src,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        vector<int>& dest_of_seg,\n        long long& min_cost\n    ) const {\n        int k = (int)segs.size();\n        vector<int> dests;\n        for (int d = 0; d < m; d++) if (d != src) dests.push_back(d);\n        int D = (int)dests.size();\n        if (k > D) return false;\n\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> cost(k, vector<long long>(D, INF));\n\n        for (int sidx = 0; sidx < k; sidx++) {\n            int l = segs[sidx].first, r = segs[sidx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n            int chunk_bottom = chunk.front();\n\n            for (int di = 0; di < D; di++) {\n                int d = dests[di];\n                long long c = 0;\n                c += 1LL * P.dest_inv_w * cross_inv_cost(st[d], chunk, cur);\n                c += 1LL * P.size_w * (int)st[d].size();\n\n                if (st[d].empty()) {\n                    c -= P.empty_bonus;\n                } else {\n                    int top = st[d].back();\n                    int fit_pen = 0;\n                    if (top > chunk_bottom) fit_pen = top - chunk_bottom;\n                    else fit_pen = P.bad_fit_base + P.bad_fit_mul * (chunk_bottom - top);\n                    c += 1LL * P.fit_w * fit_pen;\n\n                    int soon = max(0, 30 - (top - cur));\n                    c += 1LL * P.top_w * soon;\n                }\n                cost[sidx][di] = c;\n            }\n        }\n\n        int FULL = 1 << D;\n        vector<vector<long long>> dp(k + 1, vector<long long>(FULL, INF));\n        vector<vector<int>> prv_mask(k + 1, vector<int>(FULL, -1));\n        vector<vector<int>> prv_dst(k + 1, vector<int>(FULL, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < k; i++) {\n            for (int mask = 0; mask < FULL; mask++) {\n                if (dp[i][mask] == INF) continue;\n                for (int di = 0; di < D; di++) {\n                    if ((mask >> di) & 1) continue;\n                    long long cand = dp[i][mask] + cost[i][di];\n                    int nmask = mask | (1 << di);\n                    if (cand < dp[i + 1][nmask]) {\n                        dp[i + 1][nmask] = cand;\n                        prv_mask[i + 1][nmask] = mask;\n                        prv_dst[i + 1][nmask] = di;\n                    }\n                }\n            }\n        }\n\n        min_cost = INF;\n        int best_mask = -1;\n        for (int mask = 0; mask < FULL; mask++) {\n            if (dp[k][mask] < min_cost) {\n                min_cost = dp[k][mask];\n                best_mask = mask;\n            }\n        }\n        if (best_mask == -1) return false;\n\n        dest_of_seg.assign(k, -1);\n        int mask = best_mask;\n        for (int i = k; i >= 1; i--) {\n            int di = prv_dst[i][mask];\n            dest_of_seg[i - 1] = dests[di];\n            mask = prv_mask[i][mask];\n        }\n        return true;\n    }\n\n    long long global_potential(const vector<vector<int>>& st, int cur) const {\n        long long p = 0;\n        for (const auto& s : st) {\n            int h = (int)s.size();\n            for (int i = 0; i < h; i++) {\n                int w = urgency(s[i], cur);\n                for (int j = i + 1; j < h; j++) {\n                    if (s[i] < s[j]) p += w;\n                }\n            }\n        }\n        return p;\n    }\n\n    long long future_blockers_score(const vector<vector<int>>& st, int cur, int depth) const {\n        long long res = 0;\n        for (int z = cur; z <= n && z < cur + depth; z++) {\n            auto [si, pos] = find_box(st, z);\n            int blockers = (int)st[si].size() - pos - 1;\n            int w = depth - (z - cur);\n            res += 1LL * w * blockers;\n        }\n        return res;\n    }\n\n    long long structural_cost(\n        uint32_t mask,\n        int t,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        auto segs = decode_mask(t, mask);\n        int k = (int)segs.size();\n        long long inv = 0, adj = 0;\n        for (auto [l, r] : segs) {\n            inv += invw[l][r];\n            adj += adjw[l][r];\n        }\n        return 1LL * P.move_pen * k + 1LL * P.seg_inv_w * inv + 1LL * P.seg_adj_w * adj;\n    }\n\n    vector<uint32_t> generate_candidate_masks(\n        const vector<int>& blockers,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        int t = (int)blockers.size();\n        vector<uint32_t> masks;\n        masks.push_back(0); // one chunk\n\n        if (P.use_dec_runs) {\n            masks.push_back(decreasing_runs_mask(blockers, P.max_chunks, invw));\n        }\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen1));\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen2));\n        masks.push_back(partition_by_metric(adjw, t, P.max_chunks, P.gen_pen3));\n\n        if (t >= 2) {\n            vector<pair<int,int>> candB;\n            for (int i = 0; i + 1 < t; i++) {\n                int rise = max(0, blockers[i + 1] - blockers[i]);\n                int small_bonus = max(0, 120 - blockers[i + 1]);\n                int score = 4 * rise + small_bonus;\n                candB.push_back({score, i});\n            }\n            sort(candB.begin(), candB.end(), [&](auto a, auto b) {\n                if (a.first != b.first) return a.first > b.first;\n                return a.second < b.second;\n            });\n            int B = min(P.boundary_B, (int)candB.size());\n            vector<int> idxs;\n            for (int i = 0; i < B; i++) idxs.push_back(candB[i].second);\n\n            int FULL = 1 << B;\n            for (int s = 1; s < FULL; s++) {\n                if (__builtin_popcount((unsigned)s) > P.max_chunks - 1) continue;\n                uint32_t mask = 0;\n                for (int i = 0; i < B; i++) {\n                    if ((s >> i) & 1) mask |= (1U << idxs[i]);\n                }\n                masks.push_back(mask);\n            }\n        }\n\n        sort(masks.begin(), masks.end());\n        masks.erase(unique(masks.begin(), masks.end()), masks.end());\n\n        vector<pair<long long,uint32_t>> scored;\n        scored.reserve(masks.size());\n        for (uint32_t mask : masks) {\n            auto segs = decode_mask(t, mask);\n            int k = (int)segs.size();\n            if (k > P.max_chunks || k > m - 1) continue;\n            scored.push_back({structural_cost(mask, t, invw, adjw, P), mask});\n        }\n\n        sort(scored.begin(), scored.end());\n        vector<uint32_t> res;\n        int keep = min(P.shortlist, (int)scored.size());\n        for (int i = 0; i < keep; i++) res.push_back(scored[i].second);\n        return res;\n    }\n\n    struct EvalCand {\n        long long score;\n        long long assign_cost;\n        vector<pair<int,int>> segs;\n        vector<int> dests;\n    };\n\n    EvalCand choose_best_action(\n        const vector<vector<int>>& st,\n        int cur,\n        int src,\n        int pos,\n        const vector<int>& blockers,\n        const Policy& P,\n        XorShift64& rng\n    ) const {\n        int t = (int)blockers.size();\n\n        vector<vector<long long>> invw(t, vector<long long>(t, 0));\n        vector<vector<long long>> adjw(t, vector<long long>(t, 0));\n\n        for (int l = 0; l < t; l++) {\n            long long inv = 0, adj = 0;\n            for (int r = l; r < t; r++) {\n                if (r > l && blockers[r - 1] < blockers[r]) adj++;\n                for (int i = l; i < r; i++) {\n                    if (blockers[i] < blockers[r]) inv += urgency(blockers[i], cur);\n                }\n                invw[l][r] = inv;\n                adjw[l][r] = adj;\n            }\n        }\n\n        vector<uint32_t> cand_masks = generate_candidate_masks(blockers, invw, adjw, P);\n\n        EvalCand best;\n        best.score = (1LL << 60);\n\n        for (uint32_t mask : cand_masks) {\n            auto segs = decode_mask(t, mask);\n            vector<int> dests;\n            long long assign_cost;\n            if (!assign_unique_destinations(st, src, cur, segs, blockers, P, dests, assign_cost)) continue;\n\n            vector<vector<int>> st2 = st;\n            int old_cur = cur;\n\n            for (int idx = (int)segs.size() - 1; idx >= 0; idx--) {\n                int l = segs[idx].first;\n                int start = pos + 1 + l;\n                int dst = dests[idx];\n\n                vector<int> seg(st2[src].begin() + start, st2[src].end());\n                st2[src].erase(st2[src].begin() + start, st2[src].end());\n                st2[dst].insert(st2[dst].end(), seg.begin(), seg.end());\n            }\n\n            int cur2 = cur;\n            remove_possible_state_only(st2, cur2);\n\n            int immediate_energy = t + (int)segs.size();\n            int extra_removed = (cur2 - old_cur) - 1; // cur itself is always removed after exposing\n            long long gp = global_potential(st2, cur2);\n            long long fb = future_blockers_score(st2, cur2, P.future_depth);\n\n            long long score = 0;\n            score += 1LL * P.final_move_w * immediate_energy;\n            score += 1LL * P.final_assign_w * assign_cost;\n            score += 1LL * P.final_global_w * gp;\n            score += 1LL * P.final_future_w * fb;\n            score -= 1LL * P.final_removed_bonus * extra_removed;\n            score += rng.next_int(0, 2);\n\n            if (score < best.score) {\n                best.score = score;\n                best.assign_cost = assign_cost;\n                best.segs = segs;\n                best.dests = dests;\n            }\n        }\n\n        if (best.segs.empty()) {\n            best.segs = {{0, t - 1}};\n            for (int d = 0; d < m; d++) if (d != src) {\n                best.dests = {d};\n                break;\n            }\n            best.score = 0;\n            best.assign_cost = 0;\n        }\n\n        return best;\n    }\n\n    Result run_one(const Policy& P, XorShift64& rng) const {\n        vector<vector<int>> st = init_st;\n        vector<pair<int,int>> ops;\n        long long energy = 0;\n        int cur = 1;\n\n        remove_possible(st, ops, cur);\n\n        while (cur <= n) {\n            auto [src, pos] = find_box(st, cur);\n            vector<int> blockers(st[src].begin() + pos + 1, st[src].end());\n\n            if (blockers.empty()) {\n                remove_possible(st, ops, cur);\n                continue;\n            }\n\n            EvalCand best = choose_best_action(st, cur, src, pos, blockers, P, rng);\n\n            for (int idx = (int)best.segs.size() - 1; idx >= 0; idx--) {\n                int l = best.segs[idx].first;\n                int start = pos + 1 + l;\n                int dst = best.dests[idx];\n\n                int moved = (int)st[src].size() - start;\n                energy += moved + 1;\n                ops.push_back({st[src][start], dst + 1});\n\n                vector<int> seg(st[src].begin() + start, st[src].end());\n                st[src].erase(st[src].begin() + start, st[src].end());\n                st[dst].insert(st[dst].end(), seg.begin(), seg.end());\n            }\n\n            remove_possible(st, ops, cur);\n        }\n\n        return {energy, ops};\n    }\n\n    Result solve() const {\n        uint64_t seed = 0x123456789abcdef0ULL;\n        for (const auto& s : init_st) for (int x : s) seed = splitmix64(seed ^ (uint64_t)x);\n        XorShift64 rng(seed);\n\n        vector<Policy> bases = {\n            {4, 20, 7, 14,3, 9, 7,3,2,1,20,24,3, 340,1,6,28,420,4, 4,7,9, true},\n            {5, 24, 7, 12,2, 8, 7,3,2,1,22,24,3, 320,1,6,26,430,4, 3,6,8, true},\n            {4, 18, 6, 16,4,10, 8,4,2,1,18,26,3, 360,1,7,30,400,4, 5,8,10,true},\n            {5, 22, 8, 11,2, 7, 6,2,1,1,24,22,2, 300,1,5,24,470,5, 3,5,7, true},\n            {4, 20, 7, 15,3,11, 8,3,3,1,18,26,4, 350,1,7,32,390,5, 4,7,10,false}\n        };\n\n        Result best{(1LL << 60), {}};\n\n        auto start_time = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            auto now = chrono::steady_clock::now();\n            return chrono::duration<double, milli>(now - start_time).count();\n        };\n\n        for (const auto& p : bases) {\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        while (elapsed_ms() < 1850.0) {\n            Policy p = bases[rng.next_int(0, (int)bases.size() - 1)];\n\n            auto perturb = [&](int v, int d, int lo, int hi) {\n                return max(lo, min(hi, v + rng.next_int(-d, d)));\n            };\n\n            p.max_chunks         = perturb(p.max_chunks,         1, 3, 5);\n            p.shortlist          = perturb(p.shortlist,          4, 12, 30);\n            p.boundary_B         = perturb(p.boundary_B,         1, 5, 8);\n\n            p.move_pen           = perturb(p.move_pen,           3, 8, 20);\n            p.seg_inv_w          = perturb(p.seg_inv_w,          2, 0, 6);\n            p.seg_adj_w          = perturb(p.seg_adj_w,          3, 4, 14);\n\n            p.dest_inv_w         = perturb(p.dest_inv_w,         2, 4, 10);\n            p.fit_w              = perturb(p.fit_w,              1, 1, 5);\n            p.top_w              = perturb(p.top_w,              1, 0, 4);\n            p.size_w             = perturb(p.size_w,             1, 0, 3);\n            p.empty_bonus        = perturb(p.empty_bonus,        4, 10, 28);\n            p.bad_fit_base       = perturb(p.bad_fit_base,       4, 16, 30);\n            p.bad_fit_mul        = perturb(p.bad_fit_mul,        1, 1, 4);\n\n            p.final_move_w       = perturb(p.final_move_w,      40, 240, 420);\n            p.final_assign_w     = perturb(p.final_assign_w,     0, 1, 2);\n            p.final_global_w     = perturb(p.final_global_w,     2, 3, 10);\n            p.final_future_w     = perturb(p.final_future_w,     4, 18, 40);\n            p.final_removed_bonus= perturb(p.final_removed_bonus,50, 280, 520);\n            p.future_depth       = perturb(p.future_depth,       1, 3, 6);\n\n            p.gen_pen1           = perturb(p.gen_pen1,           2, 1, 8);\n            p.gen_pen2           = perturb(p.gen_pen2,           2, 3, 10);\n            p.gen_pen3           = perturb(p.gen_pen3,           3, 4, 12);\n            if (p.gen_pen1 > p.gen_pen2) swap(p.gen_pen1, p.gen_pen2);\n            p.use_dec_runs = (rng.next() & 1ULL) ? p.use_dec_runs : !p.use_dec_runs;\n\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        return best;\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>> st(m, vector<int>(n / m));\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < n / m; j++) cin >> st[i][j];\n    }\n\n    Simulator sim(n, m, st);\n    Result res = sim.solve();\n\n    for (auto [v, i] : res.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(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() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\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 EvalResult {\n    long double score;\n    vector<long long> contrib;\n    vector<int> cnt_in;\n};\n\nstruct Candidate {\n    vector<int> wps;\n    vector<int> seq;\n    long double score;\n};\n\nstatic constexpr long double INF_SCORE = 1e100L;\n\nint N, Vn;\nvector<vector<int>> g;\nvector<int> dirt;\nvector<double> potv;\n\nvector<uint16_t> distmat;\nvector<uint16_t> parmat;\n\ninline int VID(int r, int c) { return r * N + c; }\ninline uint16_t& DIST(int s, int t) { return distmat[s * Vn + t]; }\ninline uint16_t& PAR(int s, int t) { return parmat[s * Vn + t]; }\n\nEvalResult evaluate_route(const vector<int>& seq, bool detail = true) {\n    int L = (int)seq.size() - 1;\n    if (L <= 0) return {INF_SCORE, {}, {}};\n\n    vector<int> first(Vn, -1), last(Vn, -1), cnt(Vn, 0);\n    vector<long long> gapsum(Vn, 0);\n\n    for (int t = 1; t <= L; t++) {\n        int v = seq[t];\n        cnt[v]++;\n        if (first[v] == -1) {\n            first[v] = last[v] = t;\n        } else {\n            long long gap = t - last[v];\n            gapsum[v] += gap * (gap - 1) / 2;\n            last[v] = t;\n        }\n    }\n\n    long double total = 0;\n    vector<long long> contrib;\n    if (detail) contrib.assign(Vn, 0);\n\n    for (int v = 0; v < Vn; v++) {\n        if (cnt[v] == 0) return {INF_SCORE, {}, {}};\n        long long gap = first[v] + L - last[v];\n        gapsum[v] += gap * (gap - 1) / 2;\n        long long c = gapsum[v] * 1LL * dirt[v];\n        total += (long double)c;\n        if (detail) contrib[v] = c;\n    }\n\n    EvalResult res;\n    res.score = total / (long double)L;\n    if (detail) {\n        res.contrib = move(contrib);\n        res.cnt_in = move(cnt);\n    }\n    return res;\n}\n\nbool route_visits_all(const vector<int>& seq) {\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    for (int v : seq) seen[v] = 1;\n    for (int i = 0; i < Vn; i++) if (!seen[i]) return false;\n    return true;\n}\n\nvoid reconstruct_path_vertices(int s, int t, vector<int>& out) {\n    out.clear();\n    if (s == t) {\n        out.push_back(s);\n        return;\n    }\n    int cur = t;\n    out.push_back(t);\n    while (cur != s) {\n        cur = PAR(s, cur);\n        out.push_back(cur);\n    }\n    reverse(out.begin(), out.end());\n}\n\nbool append_path_mark(vector<int>& seq, int s, int t, vector<char>& seen, int& seen_cnt) {\n    if (s == t) return true;\n    static vector<int> path;\n    reconstruct_path_vertices(s, t, path);\n    for (int i = 1; i < (int)path.size(); i++) {\n        int v = path[i];\n        seq.push_back(v);\n        if (!seen[v]) {\n            seen[v] = 1;\n            seen_cnt++;\n        }\n        if ((int)seq.size() - 1 > 100000) return false;\n    }\n    return true;\n}\n\nbool build_route_from_waypoints(const vector<int>& wps, vector<int>& seq) {\n    seq.clear();\n    seq.push_back(0);\n\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n\n    for (int x : wps) {\n        if (seen[x]) continue;\n        if (!append_path_mark(seq, cur, x, seen, seen_cnt)) return false;\n        cur = x;\n    }\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        uint16_t bestd = numeric_limits<uint16_t>::max();\n        double bestpot = -1;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            uint16_t d = DIST(cur, v);\n            if (d < bestd || (d == bestd && potv[v] > bestpot)) {\n                bestd = d;\n                bestpot = potv[v];\n                best = v;\n            }\n        }\n        if (best == -1) break;\n        if (!append_path_mark(seq, cur, best, seen, seen_cnt)) return false;\n        cur = best;\n    }\n\n    if (!append_path_mark(seq, cur, 0, seen, seen_cnt)) return false;\n    return route_visits_all(seq);\n}\n\nCandidate make_candidate_from_wps(const vector<int>& wps) {\n    Candidate c;\n    c.wps = wps;\n    if (!build_route_from_waypoints(c.wps, c.seq)) {\n        c.score = INF_SCORE;\n        return c;\n    }\n    c.score = evaluate_route(c.seq, false).score;\n    return c;\n}\n\nvector<int> make_row_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; j++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int j = N - 1; j >= 0; j--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nvector<int> make_col_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int j = 0; j < N; j++) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; i++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int i = N - 1; i >= 0; i--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nuint64_t morton_code(int x, int y) {\n    uint64_t z = 0;\n    for (int b = 0; b < 6; b++) {\n        z |= ((uint64_t)((x >> b) & 1)) << (2 * b);\n        z |= ((uint64_t)((y >> b) & 1)) << (2 * b + 1);\n    }\n    return z;\n}\n\nvector<int> make_morton() {\n    vector<pair<uint64_t, int>> arr;\n    arr.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int v = VID(i, j);\n        if (v != 0) arr.push_back({morton_code(i, j), v});\n    }\n    sort(arr.begin(), arr.end());\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (auto& p : arr) ord.push_back(p.second);\n    return ord;\n}\n\nvector<int> make_pot_desc() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int v = 1; v < Vn; v++) ord.push_back(v);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (potv[a] != potv[b]) return potv[a] > potv[b];\n        return dirt[a] > dirt[b];\n    });\n    return ord;\n}\n\nvector<int> make_bfs_order() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    vector<char> vis(Vn, 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        if (v != 0) ord.push_back(v);\n        for (int to : g[v]) if (!vis[to]) {\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_dfs_order() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    vector<char> vis(Vn, 0);\n    vector<int> st = {0};\n    while (!st.empty()) {\n        int v = st.back();\n        st.pop_back();\n        if (vis[v]) continue;\n        vis[v] = 1;\n        if (v != 0) ord.push_back(v);\n        for (int i = (int)g[v].size() - 1; i >= 0; i--) {\n            int to = g[v][i];\n            if (!vis[to]) st.push_back(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_greedy_waypoints(double alpha, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double d = (double)DIST(cur, v);\n            double sc = potv[v] / pow(d + 1.0, alpha) + noise * rng.next_double();\n            if (sc > best_sc) {\n                best_sc = sc;\n                best = v;\n            }\n        }\n\n        if (best == -1) break;\n        wps.push_back(best);\n\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) {\n            if (!seen[x]) {\n                seen[x] = 1;\n                seen_cnt++;\n            }\n        }\n        cur = best;\n    }\n    return wps;\n}\n\nvector<int> make_greedy_mix(double lam, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double sc = potv[v] - lam * (double)DIST(cur, v) + noise * rng.next_double();\n            if (sc > best_sc) {\n                best_sc = sc;\n                best = v;\n            }\n        }\n\n        if (best == -1) break;\n        wps.push_back(best);\n\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) {\n            if (!seen[x]) {\n                seen[x] = 1;\n                seen_cnt++;\n            }\n        }\n        cur = best;\n    }\n    return wps;\n}\n\n// New: choose next target by uncovered value along the whole shortest path.\nvector<int> make_density_waypoints(double beta_return, double gamma_end, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double unc = 0.0;\n            int x = v;\n            while (x != cur) {\n                if (!seen[x]) unc += potv[x];\n                x = PAR(cur, x);\n            }\n            double len = (double)DIST(cur, v);\n            double ret = (double)DIST(v, 0);\n            double sc = unc / (len + beta_return * ret + 1.0)\n                      + gamma_end * potv[v] / (len + 1.0)\n                      + noise * rng.next_double();\n            if (sc > best_sc) {\n                best_sc = sc;\n                best = v;\n            }\n        }\n\n        if (best == -1) break;\n        wps.push_back(best);\n\n        int x = best;\n        vector<int> tmp;\n        reconstruct_path_vertices(cur, best, tmp);\n        for (int y : tmp) {\n            if (!seen[y]) {\n                seen[y] = 1;\n                seen_cnt++;\n            }\n        }\n        cur = best;\n    }\n    return wps;\n}\n\nstring seq_to_moves(const vector<int>& seq) {\n    string ans;\n    ans.reserve(seq.size());\n    for (int i = 1; i < (int)seq.size(); i++) {\n        int a = seq[i - 1], b = seq[i];\n        int ar = a / N, ac = a % N;\n        int br = b / N, bc = b % N;\n        if (br == ar - 1 && bc == ac) ans.push_back('U');\n        else if (br == ar + 1 && bc == ac) ans.push_back('D');\n        else if (br == ar && bc == ac - 1) ans.push_back('L');\n        else if (br == ar && bc == ac + 1) ans.push_back('R');\n        else ans.push_back('?');\n    }\n    return ans;\n}\n\nvector<int> build_segment_anchor_to_x(int anchor, int x) {\n    vector<int> path;\n    reconstruct_path_vertices(anchor, x, path);\n    vector<int> seg;\n    for (int i = 1; i < (int)path.size(); i++) seg.push_back(path[i]);\n    for (int i = (int)path.size() - 2; i >= 0; i--) seg.push_back(path[i]);\n    return seg;\n}\n\nvector<int> build_segment_anchor_x_y(int anchor, int x, int y) {\n    vector<int> p1, p2, p3;\n    reconstruct_path_vertices(anchor, x, p1);\n    reconstruct_path_vertices(x, y, p2);\n    reconstruct_path_vertices(y, anchor, p3);\n\n    vector<int> seg;\n    for (int i = 1; i < (int)p1.size(); i++) seg.push_back(p1[i]);\n    for (int i = 1; i < (int)p2.size(); i++) seg.push_back(p2[i]);\n    for (int i = 1; i < (int)p3.size(); i++) seg.push_back(p3[i]);\n    return seg;\n}\n\nvector<int> apply_segment_periodic(\n    const vector<int>& seq,\n    int anchor,\n    const vector<int>& seg,\n    int step,\n    int offset\n) {\n    int L = (int)seq.size() - 1;\n    vector<int> res;\n    res.reserve(min(100000, L + 1 + 20000));\n    res.push_back(seq[0]);\n\n    int occ = 0;\n    bool inserted = false;\n\n    for (int i = 0; i < L; i++) {\n        int cur = seq[i];\n        if (cur == anchor) {\n            if (occ % step == offset) {\n                for (int x : seg) {\n                    res.push_back(x);\n                    if ((int)res.size() - 1 > 100000) return {};\n                }\n                inserted = true;\n            }\n            occ++;\n        }\n        res.push_back(seq[i + 1]);\n        if ((int)res.size() - 1 > 100000) return {};\n    }\n\n    if (!inserted) return {};\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    Vn = N * N;\n\n    vector<string> h(N - 1), vstr(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vstr[i];\n\n    dirt.assign(Vn, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        cin >> dirt[VID(i, j)];\n    }\n\n    g.assign(Vn, {});\n    for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) {\n        if (h[i][j] == '0') {\n            int a = VID(i, j), b = VID(i + 1, j);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n    for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) {\n        if (vstr[i][j] == '0') {\n            int a = VID(i, j), b = VID(i, j + 1);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n\n    potv.assign(Vn, 0.0);\n    for (int s = 0; s < Vn; s++) {\n        potv[s] += dirt[s];\n        vector<int> dist(Vn, -1);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int x = q.front(); q.pop();\n            if (dist[x] == 3) continue;\n            for (int to : g[x]) {\n                if (dist[to] != -1) continue;\n                dist[to] = dist[x] + 1;\n                q.push(to);\n                if (dist[to] == 1) potv[s] += 0.50 * dirt[to];\n                else if (dist[to] == 2) potv[s] += 0.20 * dirt[to];\n                else if (dist[to] == 3) potv[s] += 0.08 * dirt[to];\n            }\n        }\n    }\n\n    for (int v = 0; v < Vn; v++) {\n        sort(g[v].begin(), g[v].end(), [&](int a, int b) {\n            if (potv[a] != potv[b]) return potv[a] > potv[b];\n            return dirt[a] > dirt[b];\n        });\n    }\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    distmat.assign((size_t)Vn * Vn, (uint16_t)0);\n    parmat.assign((size_t)Vn * Vn, (uint16_t)0);\n\n    vector<int> q(Vn);\n    vector<double> bestval(Vn);\n\n    for (int s = 0; s < Vn; s++) {\n        vector<int> order;\n        order.reserve(Vn);\n\n        for (int i = 0; i < Vn; i++) DIST(s, i) = numeric_limits<uint16_t>::max();\n        int qh = 0, qt = 0;\n        q[qt++] = s;\n        DIST(s, s) = 0;\n        while (qh < qt) {\n            int v = q[qh++];\n            order.push_back(v);\n            uint16_t dv = DIST(s, v);\n            for (int to : g[v]) {\n                if (DIST(s, to) == numeric_limits<uint16_t>::max()) {\n                    DIST(s, to) = dv + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        for (int i = 0; i < Vn; i++) {\n            bestval[i] = -1e100;\n            PAR(s, i) = (uint16_t)i;\n        }\n        bestval[s] = potv[s];\n        PAR(s, s) = (uint16_t)s;\n\n        for (int v : order) {\n            for (int to : g[v]) {\n                if (DIST(s, to) == DIST(s, v) + 1) {\n                    double nv = bestval[v] + potv[to];\n                    if (nv > bestval[to] + 1e-12) {\n                        bestval[to] = nv;\n                        PAR(s, to) = (uint16_t)v;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Candidate> cands;\n\n    auto add_candidate = [&](const vector<int>& wps) {\n        Candidate c = make_candidate_from_wps(wps);\n        if (c.score < INF_SCORE) cands.push_back(move(c));\n    };\n\n    add_candidate(make_row_snake());\n    add_candidate(make_col_snake());\n    add_candidate(make_morton());\n    add_candidate(make_pot_desc());\n    add_candidate(make_bfs_order());\n    add_candidate(make_dfs_order());\n\n    add_candidate(make_greedy_waypoints(0.9, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.2, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.6, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.2, 30.0, rng));\n    add_candidate(make_greedy_mix(8.0, 20.0, rng));\n    add_candidate(make_greedy_mix(14.0, 30.0, rng));\n\n    // New density-based builders.\n    add_candidate(make_density_waypoints(0.0, 0.05, 0.0, rng));\n    add_candidate(make_density_waypoints(0.2, 0.05, 0.0, rng));\n    add_candidate(make_density_waypoints(0.5, 0.08, 10.0, rng));\n\n    while (timer.elapsed() < 0.58) {\n        int t = rng.next_int(3);\n        if (t == 0) {\n            double alpha = 0.8 + 1.4 * rng.next_double();\n            double noise = 10.0 + 60.0 * rng.next_double();\n            add_candidate(make_greedy_waypoints(alpha, noise, rng));\n        } else if (t == 1) {\n            double lam = 6.0 + 16.0 * rng.next_double();\n            double noise = 10.0 + 50.0 * rng.next_double();\n            add_candidate(make_greedy_mix(lam, noise, rng));\n        } else {\n            double beta = 0.0 + 0.9 * rng.next_double();\n            double gamma = 0.02 + 0.10 * rng.next_double();\n            double noise = 0.0 + 20.0 * rng.next_double();\n            add_candidate(make_density_waypoints(beta, gamma, noise, rng));\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n        return a.score < b.score;\n    });\n    if (cands.empty()) {\n        auto c = make_candidate_from_wps(make_row_snake());\n        cout << seq_to_moves(c.seq) << '\\n';\n        return 0;\n    }\n    if ((int)cands.size() > 6) cands.resize(6);\n\n    Candidate best = cands[0];\n\n    // Local search on waypoints.\n    {\n        Candidate cur = best;\n\n        if (!cur.wps.empty()) {\n            vector<int> order = cur.wps;\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return potv[a] < potv[b];\n            });\n            for (int v : order) {\n                if (timer.elapsed() > 1.18) break;\n                int pos = -1;\n                for (int i = 0; i < (int)cur.wps.size(); i++) {\n                    if (cur.wps[i] == v) { pos = i; break; }\n                }\n                if (pos == -1) continue;\n                vector<int> nwps = cur.wps;\n                nwps.erase(nwps.begin() + pos);\n                Candidate cand = make_candidate_from_wps(nwps);\n                if (cand.score + 1e-12L < cur.score) cur = move(cand);\n            }\n        }\n\n        vector<int> hot_vertices;\n        for (int v = 1; v < Vn; v++) hot_vertices.push_back(v);\n        sort(hot_vertices.begin(), hot_vertices.end(), [&](int a, int b) {\n            if (potv[a] != potv[b]) return potv[a] > potv[b];\n            return dirt[a] > dirt[b];\n        });\n        if ((int)hot_vertices.size() > 80) hot_vertices.resize(80);\n\n        while (timer.elapsed() < 1.56 && !cur.wps.empty()) {\n            vector<int> nwps = cur.wps;\n            int m = (int)nwps.size();\n            int op = rng.next_int(6);\n\n            if (op == 0 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i > j) swap(i, j);\n                if (i == j) continue;\n                swap(nwps[i], nwps[j]);\n            } else if (op == 1 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i > j) swap(i, j);\n                if (i == j) continue;\n                reverse(nwps.begin() + i, nwps.begin() + j + 1);\n            } else if (op == 2 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i == j) continue;\n                int v = nwps[i];\n                nwps.erase(nwps.begin() + i);\n                if (j > i) j--;\n                nwps.insert(nwps.begin() + j, v);\n            } else if (op == 3 && m >= 1) {\n                int i = rng.next_int(m);\n                nwps.erase(nwps.begin() + i);\n            } else if (op == 4 && m >= 1) {\n                int i = rng.next_int(m);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool exists = false;\n                for (int y : nwps) if (y == x) { exists = true; break; }\n                if (exists) continue;\n                nwps[i] = x;\n            } else if (op == 5 && m >= 1) {\n                int pos = rng.next_int(m + 1);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool exists = false;\n                for (int y : nwps) if (y == x) { exists = true; break; }\n                if (exists) continue;\n                nwps.insert(nwps.begin() + pos, x);\n            } else {\n                continue;\n            }\n\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + 1e-12L < cur.score) cur = move(cand);\n        }\n\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    for (int idx = 1; idx < (int)cands.size() && timer.elapsed() < 1.66; idx++) {\n        Candidate cur = cands[idx];\n        int trials = min(70, (int)cur.wps.size() + 10);\n        for (int t = 0; t < trials && timer.elapsed() < 1.66; t++) {\n            if (cur.wps.empty()) break;\n            vector<int> nwps = cur.wps;\n            int op = rng.next_int(2);\n            if (op == 0) {\n                int i = rng.next_int((int)nwps.size());\n                nwps.erase(nwps.begin() + i);\n            } else {\n                int i = rng.next_int((int)nwps.size());\n                int j = rng.next_int((int)nwps.size());\n                swap(nwps[i], nwps[j]);\n            }\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + 1e-12L < cur.score) cur = move(cand);\n        }\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    vector<int> cur_seq = best.seq;\n    EvalResult cur_ev = evaluate_route(cur_seq, true);\n\n    const vector<pair<int,int>> patterns = {\n        {1,0},\n        {2,0},{2,1},\n        {3,0},{3,1},{3,2},\n        {4,0},{4,1},{4,2},{4,3},\n        {5,0},{5,1},{5,2},{5,3},{5,4}\n    };\n\n    for (int round = 0; round < 10 && timer.elapsed() < 1.93; round++) {\n        int L = (int)cur_seq.size() - 1;\n        if (L > 98000) break;\n\n        vector<int> rankv(Vn);\n        iota(rankv.begin(), rankv.end(), 0);\n        sort(rankv.begin(), rankv.end(), [&](int a, int b) {\n            return cur_ev.contrib[a] > cur_ev.contrib[b];\n        });\n\n        vector<int> occ_pos_cnt(Vn, 0);\n        for (int i = 0; i < L; i++) occ_pos_cnt[cur_seq[i]]++;\n\n        long double best_sc = cur_ev.score;\n        vector<int> best_seq2;\n\n        int TOPX = min(Vn, 16);\n        for (int ii = 0; ii < TOPX && timer.elapsed() < 1.92; ii++) {\n            int x = rankv[ii];\n\n            vector<pair<double,int>> anchors;\n            for (int a = 0; a < Vn; a++) {\n                if (a == x || occ_pos_cnt[a] == 0) continue;\n                int d = DIST(a, x);\n                if (d == 0) continue;\n                if (d > 12 && occ_pos_cnt[a] <= 1) continue;\n                double sc = (double)occ_pos_cnt[a] / (double)(d + 1) + 0.001 * potv[a];\n                anchors.push_back({-sc, a});\n            }\n            sort(anchors.begin(), anchors.end());\n            if ((int)anchors.size() > 6) anchors.resize(6);\n\n            // One-target excursion.\n            for (auto &pa : anchors) {\n                int a = pa.second;\n                vector<int> seg = build_segment_anchor_to_x(a, x);\n                if (seg.empty()) continue;\n                for (auto [step, off] : patterns) {\n                    auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                    if (cand_seq.empty()) continue;\n                    auto ev = evaluate_route(cand_seq, false);\n                    if (ev.score + 1e-12L < best_sc) {\n                        best_sc = ev.score;\n                        best_seq2 = move(cand_seq);\n                    }\n                }\n            }\n\n            // Two-target excursion for hotspot clusters.\n            vector<int> ycand;\n            for (int jj = 0; jj < min(Vn, 40) && (int)ycand.size() < 4; jj++) {\n                int y = rankv[jj];\n                if (y == x) continue;\n                int dxy = DIST(x, y);\n                if (dxy <= 6) ycand.push_back(y);\n            }\n\n            for (int y : ycand) {\n                for (auto &pa : anchors) {\n                    int a = pa.second;\n                    int cyc_len = DIST(a, x) + DIST(x, y) + DIST(y, a);\n                    if (cyc_len > 20) continue;\n                    vector<int> seg = build_segment_anchor_x_y(a, x, y);\n                    if (seg.empty()) continue;\n                    for (auto [step, off] : patterns) {\n                        auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                        if (cand_seq.empty()) continue;\n                        auto ev = evaluate_route(cand_seq, false);\n                        if (ev.score + 1e-12L < best_sc) {\n                            best_sc = ev.score;\n                            best_seq2 = move(cand_seq);\n                        }\n                    }\n                }\n            }\n        }\n\n        if (best_seq2.empty()) break;\n        cur_seq = move(best_seq2);\n        cur_ev = evaluate_route(cur_seq, true);\n    }\n\n    cout << seq_to_moves(cur_seq) << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int INF = 1e9;\n\nstruct Solver {\n    int N, M;\n    int si, sj;\n    vector<string> board;\n    vector<string> words;\n    vector<pair<int,int>> posByChar[26];\n\n    vector<vector<int>> ov;          // overlap length [i][j] in [0,4]\n    vector<int> startApprox;         // approximate typing cost for first word\n    vector<vector<int>> edgeApprox;  // approximate typing cost to append j after i\n    vector<int> startLen;            // = 5\n    vector<vector<int>> edgeLen;     // = 5 - overlap\n\n    inline int dist(const pair<int,int>& a, const pair<int,int>& b) const {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    int overlap5(const string& a, const string& b) {\n        for (int k = 4; k >= 0; --k) {\n            bool ok = true;\n            for (int t = 0; t < k; ++t) {\n                if (a[5 - k + t] != b[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    // Exact min cost to type string s, starting with finger already on\n    // some occurrence of prevChar, with zero initial cost.\n    int cost_from_prev_char(int prevChar, const string& s) {\n        if (s.empty()) return 0;\n        const auto& initList = posByChar[prevChar];\n        vector<int> dp(initList.size(), 0), ndp;\n        const vector<pair<int,int>>* prevList = &initList;\n\n        for (char ch : s) {\n            int c = ch - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    // Exact min cost to type string s from the initial finger position.\n    int cost_from_start(const string& s) {\n        if (s.empty()) return 0;\n        int c0 = s[0] - 'A';\n        const auto& firstList = posByChar[c0];\n        vector<int> dp(firstList.size()), ndp;\n        for (int i = 0; i < (int)firstList.size(); ++i) {\n            dp[i] = abs(si - firstList[i].first) + abs(sj - firstList[i].second) + 1;\n        }\n        const vector<pair<int,int>>* prevList = &firstList;\n\n        for (int p = 1; p < (int)s.size(); ++p) {\n            int c = s[p] - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    void preprocess() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                posByChar[board[i][j] - 'A'].push_back({i, j});\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                ov[i][j] = overlap5(words[i], words[j]);\n            }\n        }\n\n        startApprox.assign(M, 0);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        startLen.assign(M, 5);\n        edgeLen.assign(M, vector<int>(M, 5));\n\n        for (int i = 0; i < M; ++i) {\n            startApprox[i] = cost_from_start(words[i]);\n        }\n\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                int r = ov[i][j];\n                string chunk = words[j].substr(r);\n                edgeApprox[i][j] = cost_from_prev_char(words[i][4] - 'A', chunk);\n                edgeLen[i][j] = 5 - r;\n            }\n        }\n    }\n\n    int insertion_delta(\n        const vector<int>& path,\n        int x, int pos,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int m = (int)path.size();\n        if (m == 0) return startC[x];\n        if (pos == 0) {\n            return startC[x] + edgeC[x][path[0]] - startC[path[0]];\n        } else if (pos == m) {\n            return edgeC[path[m - 1]][x];\n        } else {\n            return edgeC[path[pos - 1]][x] + edgeC[x][path[pos]] - edgeC[path[pos - 1]][path[pos]];\n        }\n    }\n\n    vector<int> build_order_cheapest_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        if (a == -1) {\n            path.push_back(0);\n            used[0] = 1;\n        } else {\n            path.push_back(a);\n            used[a] = 1;\n            if (b != -1) {\n                path.push_back(b);\n                used[b] = 1;\n            }\n        }\n\n        while ((int)path.size() < M) {\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n        return path;\n    }\n\n    vector<int> improve_relocate(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int n = (int)path.size();\n        for (int iter = 0; iter < 200; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (int i = 0; i < n; ++i) {\n                int x = path[i];\n\n                int remDelta = 0;\n                if (n == 1) {\n                    remDelta = 0;\n                } else if (i == 0) {\n                    int b = path[1];\n                    remDelta = startC[b] - startC[x] - edgeC[x][b];\n                } else if (i == n - 1) {\n                    int a = path[n - 2];\n                    remDelta = -edgeC[a][x];\n                } else {\n                    int a = path[i - 1];\n                    int b = path[i + 1];\n                    remDelta = edgeC[a][b] - edgeC[a][x] - edgeC[x][b];\n                }\n\n                for (int j = 0; j <= n - 1; ++j) {\n                    if (j == i) continue; // no-op\n\n                    int left = -1, right = -1;\n                    if (j < i) {\n                        left = (j == 0 ? -1 : path[j - 1]);\n                        right = path[j];\n                    } else { // j > i\n                        left = path[j];\n                        right = (j == n - 1 ? -1 : path[j + 1]);\n                    }\n\n                    int insDelta = 0;\n                    if (left == -1) {\n                        insDelta = startC[x] + edgeC[x][right] - startC[right];\n                    } else if (right == -1) {\n                        insDelta = edgeC[left][x];\n                    } else {\n                        insDelta = edgeC[left][x] + edgeC[x][right] - edgeC[left][right];\n                    }\n\n                    int delta = remDelta + insDelta;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            int x = path[bestI];\n            path.erase(path.begin() + bestI);\n            path.insert(path.begin() + bestJ, x);\n        }\n        return path;\n    }\n\n    string build_string(const vector<int>& order) {\n        string s = words[order[0]];\n        s.reserve(5 + 4 * M);\n        for (int k = 1; k < M; ++k) {\n            int i = order[k - 1];\n            int j = order[k];\n            int r = ov[i][j];\n            s += words[j].substr(r);\n        }\n        return s;\n    }\n\n    pair<int, vector<pair<int,int>>> exact_positions_for_string(const string& s) {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n        vector<int> dp, ndp;\n        const vector<pair<int,int>>* prevList = nullptr;\n\n        for (int t = 0; t < L; ++t) {\n            int c = s[t] - 'A';\n            const auto& curList = posByChar[c];\n            parent[t].assign(curList.size(), -1);\n            ndp.assign(curList.size(), INF);\n\n            if (t == 0) {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    ndp[j] = abs(si - curList[j].first) + abs(sj - curList[j].second) + 1;\n                }\n            } else {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    int best = INF, bestPrev = -1;\n                    for (int i = 0; i < (int)prevList->size(); ++i) {\n                        int cand = dp[i] + dist((*prevList)[i], curList[j]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestPrev = i;\n                        }\n                    }\n                    ndp[j] = best;\n                    parent[t][j] = bestPrev;\n                }\n            }\n\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n\n        int lastIdx = min_element(dp.begin(), dp.end()) - dp.begin();\n        int bestCost = dp[lastIdx];\n\n        vector<pair<int,int>> ops(L);\n        int idx = lastIdx;\n        for (int t = L - 1; t >= 0; --t) {\n            int c = s[t] - 'A';\n            ops[t] = posByChar[c][idx];\n            idx = parent[t][idx];\n        }\n\n        return {bestCost, ops};\n    }\n\n    void try_objective(\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps\n    ) {\n        vector<tuple<int,int,int>> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                pairs.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(pairs.begin(), pairs.end());\n\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            auto [c, a, b] = pairs[idx];\n            (void)c;\n\n            auto order = build_order_cheapest_insertion(a, b, startC, edgeC);\n            order = improve_relocate(order, startC, edgeC);\n\n            string s = build_string(order);\n            if ((int)s.size() > 5000) continue;\n\n            auto [cost, ops] = exact_positions_for_string(s);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestOps = move(ops);\n            }\n        }\n    }\n\n    void solve() {\n        preprocess();\n\n        int bestCost = INF;\n        vector<pair<int,int>> bestOps;\n\n        if (M == 1) {\n            auto res = exact_positions_for_string(words[0]);\n            bestOps = move(res.second);\n        } else {\n            // Keyboard-aware objective\n            try_objective(startApprox, edgeApprox, 20, bestCost, bestOps);\n\n            // Length-oriented objective\n            try_objective(startLen, edgeLen, 12, bestCost, bestOps);\n\n            // Also try: build by length, then polish by typing-cost objective\n            vector<tuple<int,int,int>> pairs;\n            for (int a = 0; a < M; ++a) {\n                for (int b = 0; b < M; ++b) if (a != b) {\n                    pairs.emplace_back(startLen[a] + edgeLen[a][b], a, b);\n                }\n            }\n            sort(pairs.begin(), pairs.end());\n            int use = min(12, (int)pairs.size());\n            for (int idx = 0; idx < use; ++idx) {\n                auto [c, a, b] = pairs[idx];\n                (void)c;\n                auto order = build_order_cheapest_insertion(a, b, startLen, edgeLen);\n                order = improve_relocate(order, startLen, edgeLen);\n                order = improve_relocate(order, startApprox, edgeApprox);\n\n                string s = build_string(order);\n                if ((int)s.size() > 5000) continue;\n\n                auto [cost, ops] = exact_positions_for_string(s);\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestOps = move(ops);\n                }\n            }\n        }\n\n        // Fallback (should not happen)\n        if (bestOps.empty()) {\n            string s;\n            for (auto& w : words) s += w;\n            auto [cost, ops] = exact_positions_for_string(s);\n            bestOps = move(ops);\n        }\n\n        for (auto [i, j] : bestOps) {\n            cout << i << ' ' << j << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M;\n    cin >> solver.si >> solver.sj;\n    solver.board.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.board[i];\n    solver.words.resize(solver.M);\n    for (int i = 0; i < solver.M; ++i) cin >> solver.words[i];\n\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 20;\nstatic constexpr int MAXC = 400;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct Placement {\n    vector<uint16_t> cells;\n    bitset<MAXC> mask;\n    vector<uint8_t> contrib;   // contributions to noisy query features\n    vector<uint16_t> drill_ids; // drilled cells covered by this placement\n    bool valid = true;\n};\n\nstruct Field {\n    vector<pair<int,int>> shape;\n    vector<Placement> ps;\n    int valid_count = 0;\n};\n\nstruct SavedState {\n    array<short, MAXM> choice{};\n    int exact_err = INT_MAX;\n    double noisy = 1e100;\n};\n\nstruct SearchState {\n    array<short, MAXM> choice{};\n    vector<int> feat;\n    vector<int> pred; // predicted reserve counts on drilled cells\n    int exact_err = 0;\n    double noisy = 0.0;\n};\n\nstruct Solver {\n    int N, M;\n    double eps, alpha;\n    int C;\n\n    vector<Field> fields;\n\n    // blocks\n    int rb[5], cb[5];\n    int block_id[MAXN][MAXN];\n\n    // query sets\n    int Q = 0;\n    vector<vector<int>> query_cells;\n    vector<bitset<MAXC>> query_masks;\n    vector<double> estQ, wQ;\n    vector<int> qSize;\n\n    // reverse cover list\n    vector<vector<pair<uint8_t, uint16_t>>> coverList;\n\n    // drilled information\n    vector<int> drill_cells;\n    vector<int> drill_obs;\n    vector<int> cell_to_drill; // -1 if not drilled\n    vector<int> exact_v;       // -1 if unknown\n\n    // local search scratch\n    vector<int> mark, chg, aff;\n    int iter_mark = 1;\n\n    chrono::steady_clock::time_point st;\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool better_pair(int e1, double n1, int e2, double n2) const {\n        if (e1 != e2) return e1 < e2;\n        return n1 + 1e-12 < n2;\n    }\n\n    // ---------- interaction ----------\n\n    int ask_divination(const vector<int>& cells) {\n        cout << \"q \" << cells.size();\n        for (int id : cells) {\n            cout << ' ' << id / N << ' ' << id % N;\n        }\n        cout << endl;\n        cout.flush();\n        int y;\n        cin >> y;\n        return y;\n    }\n\n    int ask_drill(int cell) {\n        cout << \"q 1 \" << cell / N << ' ' << cell % N << endl;\n        cout.flush();\n        int v;\n        cin >> v;\n        return v;\n    }\n\n    bool ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int id : cells) {\n            cout << ' ' << id / N << ' ' << id % N;\n        }\n        cout << endl;\n        cout.flush();\n        int ok;\n        cin >> ok;\n        return ok == 1;\n    }\n\n    // ---------- setup ----------\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        alpha = 1.0 - 2.0 * eps;\n        C = N * N;\n        fields.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int d;\n            cin >> d;\n            fields[k].shape.resize(d);\n            for (int t = 0; t < d; ++t) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].shape[t] = {i, j};\n            }\n        }\n        coverList.assign(C, {});\n        cell_to_drill.assign(C, -1);\n        exact_v.assign(C, -1);\n    }\n\n    void build_blocks() {\n        for (int t = 0; t <= 4; ++t) {\n            rb[t] = (long long)t * N / 4;\n            cb[t] = (long long)t * N / 4;\n        }\n        for (int i = 0; i < N; ++i) {\n            int bi = 0;\n            while (!(rb[bi] <= i && i < rb[bi + 1])) ++bi;\n            for (int j = 0; j < N; ++j) {\n                int bj = 0;\n                while (!(cb[bj] <= j && j < cb[bj + 1])) ++bj;\n                block_id[i][j] = bi * 4 + bj;\n            }\n        }\n    }\n\n    void add_query_set(const vector<int>& cells) {\n        if ((int)cells.size() < 2) return;\n        bitset<MAXC> bs;\n        for (int id : cells) bs.set(id);\n        query_cells.push_back(cells);\n        query_masks.push_back(bs);\n    }\n\n    void build_query_sets() {\n        query_cells.clear();\n        query_masks.clear();\n\n        int mode = 0;\n        // mode 3: rows + cols + blocks + a few extra patterns\n        // mode 2: rows + cols + blocks\n        // mode 1: blocks only\n        // mode 0: quadrants only\n        if (M <= 5 && eps <= 0.15) mode = 3;\n        else if (M <= 8 && eps <= 0.12) mode = 2;\n        else if ((M <= 12 && eps <= 0.10) || (M <= 15 && eps <= 0.05)) mode = 1;\n        else mode = 0;\n\n        if (mode >= 2) {\n            for (int i = 0; i < N; ++i) {\n                vector<int> cells;\n                cells.reserve(N);\n                for (int j = 0; j < N; ++j) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n            for (int j = 0; j < N; ++j) {\n                vector<int> cells;\n                cells.reserve(N);\n                for (int i = 0; i < N; ++i) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n        }\n\n        if (mode >= 1) {\n            for (int bi = 0; bi < 4; ++bi) {\n                for (int bj = 0; bj < 4; ++bj) {\n                    vector<int> cells;\n                    for (int i = rb[bi]; i < rb[bi + 1]; ++i) {\n                        for (int j = cb[bj]; j < cb[bj + 1]; ++j) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    add_query_set(cells);\n                }\n            }\n        } else {\n            // 4 quadrants only\n            for (int bi = 0; bi < 2; ++bi) {\n                for (int bj = 0; bj < 2; ++bj) {\n                    int r0 = (long long)bi * N / 2;\n                    int r1 = (long long)(bi + 1) * N / 2;\n                    int c0 = (long long)bj * N / 2;\n                    int c1 = (long long)(bj + 1) * N / 2;\n                    vector<int> cells;\n                    for (int i = r0; i < r1; ++i) {\n                        for (int j = c0; j < c1; ++j) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    add_query_set(cells);\n                }\n            }\n        }\n\n        if (mode == 3) {\n            for (int t = 0; t < 4; ++t) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        int f = 0;\n                        if (t == 0) f = ((i + j) & 1);\n                        if (t == 1) f = (i & 1);\n                        if (t == 2) f = (j & 1);\n                        if (t == 3) f = (((i / 2) + (j / 2)) & 1);\n                        if (f) cells.push_back(i * N + j);\n                    }\n                }\n                if ((int)cells.size() >= 2 && (int)cells.size() < C) add_query_set(cells);\n            }\n        }\n\n        Q = (int)query_cells.size();\n        estQ.assign(Q, 0.0);\n        wQ.assign(Q, 0.0);\n        qSize.assign(Q, 0);\n    }\n\n    void ask_initial_queries() {\n        for (int q = 0; q < Q; ++q) {\n            int y = ask_divination(query_cells[q]);\n            int k = (int)query_cells[q].size();\n            qSize[q] = k;\n            estQ[q] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[q] = 1.0 / var_est;\n        }\n    }\n\n    void enumerate_placements() {\n        for (int k = 0; k < M; ++k) {\n            int max_i = 0, max_j = 0;\n            for (auto [i, j] : fields[k].shape) {\n                max_i = max(max_i, i);\n                max_j = max(max_j, j);\n            }\n\n            for (int di = 0; di + max_i < N; ++di) {\n                for (int dj = 0; dj + max_j < N; ++dj) {\n                    Placement p;\n                    p.contrib.assign(Q, 0);\n                    for (auto [si, sj] : fields[k].shape) {\n                        int i = di + si;\n                        int j = dj + sj;\n                        int id = i * N + j;\n                        p.cells.push_back((uint16_t)id);\n                        p.mask.set(id);\n                    }\n                    for (int q = 0; q < Q; ++q) {\n                        uint8_t c = 0;\n                        for (int id : p.cells) c += (uint8_t)query_masks[q].test(id);\n                        p.contrib[q] = c;\n                    }\n\n                    int idx = (int)fields[k].ps.size();\n                    for (int id : p.cells) {\n                        coverList[id].push_back({(uint8_t)k, (uint16_t)idx});\n                    }\n                    fields[k].ps.push_back(std::move(p));\n                }\n            }\n            fields[k].valid_count = (int)fields[k].ps.size();\n        }\n    }\n\n    // ---------- placement validity / propagation ----------\n\n    bool usable_placement(int k, int p) const {\n        return fields[k].ps[p].valid;\n    }\n\n    bool invalidate_field_by_cover_state(int k, int cell, bool must_cover) {\n        bool changed = false;\n        for (auto &pl : fields[k].ps) {\n            if (!pl.valid) continue;\n            bool cov = pl.mask.test(cell);\n            if (cov != must_cover) {\n                pl.valid = false;\n                fields[k].valid_count--;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    bool all_fields_unique(vector<int>& ans_cells) const {\n        bitset<MAXC> uni;\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count != 1) return false;\n            for (const auto &pl : fields[k].ps) {\n                if (pl.valid) {\n                    uni |= pl.mask;\n                    break;\n                }\n            }\n        }\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (uni.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    void register_drill(int cell, int v) {\n        exact_v[cell] = v;\n        if (cell_to_drill[cell] == -1) {\n            int idx = (int)drill_cells.size();\n            cell_to_drill[cell] = idx;\n            drill_cells.push_back(cell);\n            drill_obs.push_back(v);\n\n            mark.resize(drill_cells.size(), 0);\n            chg.resize(drill_cells.size(), 0);\n\n            for (auto [fk, pi] : coverList[cell]) {\n                fields[fk].ps[pi].drill_ids.push_back((uint16_t)idx);\n            }\n        } else {\n            drill_obs[cell_to_drill[cell]] = v;\n        }\n\n        if (v == 0) {\n            for (auto [fk, pi] : coverList[cell]) {\n                auto &pl = fields[fk].ps[pi];\n                if (pl.valid) {\n                    pl.valid = false;\n                    fields[fk].valid_count--;\n                }\n            }\n        }\n    }\n\n    void propagate_constraints() {\n        if (drill_cells.empty()) return;\n\n        bool changed = true;\n        while (changed) {\n            changed = false;\n\n            for (int did = 0; did < (int)drill_cells.size(); ++did) {\n                int cell = drill_cells[did];\n                int req = drill_obs[did];\n\n                int sure = 0, poss = 0;\n                vector<uint8_t> state(M, 0); // 0: none, 1: all cover, 2: mixed, 3: all not cover\n\n                for (int k = 0; k < M; ++k) {\n                    bool any0 = false, any1 = false;\n                    for (const auto &pl : fields[k].ps) {\n                        if (!pl.valid) continue;\n                        bool cov = pl.mask.test(cell);\n                        if (cov) any1 = true;\n                        else any0 = true;\n                        if (any0 && any1) break;\n                    }\n\n                    if (!any0 && !any1) {\n                        // inconsistent, but ignore and fallback later\n                        return;\n                    }\n                    if (any1 && !any0) {\n                        state[k] = 1;\n                        sure++;\n                        poss++;\n                    } else if (any1 && any0) {\n                        state[k] = 2;\n                        poss++;\n                    } else {\n                        state[k] = 3;\n                    }\n                }\n\n                if (sure > req || poss < req) {\n                    return;\n                }\n\n                if (sure == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) {\n                            changed |= invalidate_field_by_cover_state(k, cell, false);\n                        }\n                    }\n                }\n                if (poss == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) {\n                            changed |= invalidate_field_by_cover_state(k, cell, true);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // ---------- local search ----------\n\n    double initial_noisy0() const {\n        double s = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            double r = -estQ[q];\n            s += wQ[q] * r * r;\n        }\n        return s;\n    }\n\n    void calc_delta_parts(const SearchState& s, int field_idx, int newp, int &dExact, double &dNoisy) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) {\n            dExact = 0;\n            dNoisy = 0.0;\n            return;\n        }\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        dNoisy = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            dNoisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n        }\n\n        dExact = 0;\n        if (drill_cells.empty()) return;\n\n        ++iter_mark;\n        if (iter_mark == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            iter_mark = 1;\n        }\n        aff.clear();\n\n        if (oldpl) {\n            for (int id : oldpl->drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]--;\n            }\n        }\n        for (int id : newpl.drill_ids) {\n            if (mark[id] != iter_mark) {\n                mark[id] = iter_mark;\n                chg[id] = 0;\n                aff.push_back(id);\n            }\n            chg[id]++;\n        }\n\n        for (int id : aff) {\n            int oc = s.pred[id];\n            int nc = oc + chg[id];\n            int obs = drill_obs[id];\n            dExact += (nc - obs) * (nc - obs) - (oc - obs) * (oc - obs);\n        }\n    }\n\n    void apply_change(SearchState& s, int field_idx, int newp) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) return;\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            s.noisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n            s.feat[q] += d;\n        }\n\n        if (!drill_cells.empty()) {\n            ++iter_mark;\n            if (iter_mark == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                iter_mark = 1;\n            }\n            aff.clear();\n\n            if (oldpl) {\n                for (int id : oldpl->drill_ids) {\n                    if (mark[id] != iter_mark) {\n                        mark[id] = iter_mark;\n                        chg[id] = 0;\n                        aff.push_back(id);\n                    }\n                    chg[id]--;\n                }\n            }\n            for (int id : newpl.drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]++;\n            }\n\n            for (int id : aff) {\n                int oc = s.pred[id];\n                int obs = drill_obs[id];\n                s.exact_err -= (oc - obs) * (oc - obs);\n                s.pred[id] += chg[id];\n                int nc = s.pred[id];\n                s.exact_err += (nc - obs) * (nc - obs);\n            }\n        }\n\n        s.choice[field_idx] = (short)newp;\n    }\n\n    SearchState greedy_random_init() {\n        SearchState s;\n        s.choice.fill(-1);\n        s.feat.assign(Q, 0);\n        s.pred.assign(drill_cells.size(), 0);\n        s.exact_err = 0;\n        for (int obs : drill_obs) s.exact_err += obs * obs;\n        s.noisy = initial_noisy0();\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n        for (int k : order) {\n            struct Cand { int p; int e; double n; };\n            Cand best[4];\n            int bsz = 0;\n\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                int de;\n                double dn;\n                calc_delta_parts(s, k, p, de, dn);\n                int ne = s.exact_err + de;\n                double nn = s.noisy + dn;\n                Cand cur{p, ne, nn};\n\n                int pos = bsz;\n                for (int t = 0; t < bsz; ++t) {\n                    if (better_pair(cur.e, cur.n, best[t].e, best[t].n)) {\n                        pos = t;\n                        break;\n                    }\n                }\n                if (pos < 4) {\n                    for (int t = min(3, bsz); t > pos; --t) best[t] = best[t - 1];\n                    best[pos] = cur;\n                    if (bsz < 4) ++bsz;\n                }\n            }\n\n            if (bsz == 0) continue;\n            int pick = 0;\n            if (bsz >= 2) {\n                int r = rng.next_int(0, min(6, bsz * 2) - 1);\n                pick = min(r / 2, bsz - 1);\n            }\n            apply_change(s, k, best[pick].p);\n        }\n        return s;\n    }\n\n    void local_descent(SearchState& s, int max_sweeps = 4) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < max_sweeps; ++sw) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n            for (int k : order) {\n                int bestp = s.choice[k];\n                int beste = s.exact_err;\n                double bestn = s.noisy;\n\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (!usable_placement(k, p)) continue;\n                    int de;\n                    double dn;\n                    calc_delta_parts(s, k, p, de, dn);\n                    int ne = s.exact_err + de;\n                    double nn = s.noisy + dn;\n                    if (better_pair(ne, nn, beste, bestn)) {\n                        beste = ne;\n                        bestn = nn;\n                        bestp = p;\n                    }\n                }\n\n                if (bestp != s.choice[k]) {\n                    apply_change(s, k, bestp);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    static bool same_choice(const SavedState& a, const SavedState& b, int M) {\n        for (int i = 0; i < M; ++i) if (a.choice[i] != b.choice[i]) return false;\n        return true;\n    }\n\n    void add_saved(vector<SavedState>& top, const SearchState& s, int keep = 10) {\n        SavedState cur;\n        cur.choice = s.choice;\n        cur.exact_err = s.exact_err;\n        cur.noisy = s.noisy;\n\n        for (auto &x : top) {\n            if (same_choice(x, cur, M)) {\n                if (better_pair(cur.exact_err, cur.noisy, x.exact_err, x.noisy)) x = cur;\n                return;\n            }\n        }\n\n        top.push_back(cur);\n        sort(top.begin(), top.end(), [&](const SavedState& a, const SavedState& b) {\n            return better_pair(a.exact_err, a.noisy, b.exact_err, b.noisy);\n        });\n        if ((int)top.size() > keep) top.resize(keep);\n    }\n\n    vector<SavedState> search_states(int restarts) {\n        vector<SavedState> top;\n        for (int it = 0; it < restarts; ++it) {\n            if (elapsed_ms() > 2650.0) break;\n            SearchState s = greedy_random_init();\n            local_descent(s, 4);\n            add_saved(top, s, 10);\n        }\n        return top;\n    }\n\n    vector<char> union_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ(C, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = choice[k];\n            if (p < 0) continue;\n            for (int id : fields[k].ps[p].cells) occ[id] = 1;\n        }\n        return occ;\n    }\n\n    // ---------- exact enumeration ----------\n\n    bool exact_deduce_union(vector<int>& ans_cells) {\n        if (elapsed_ms() > 2550.0) return false;\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count <= 0) return false;\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return fields[a].valid_count < fields[b].valid_count;\n        });\n\n        double log_prod = 0.0;\n        for (int k : order) log_prod += log((double)max(1, fields[k].valid_count));\n        if (log_prod > log(3.0e6)) return false;\n\n        int D = (int)drill_cells.size();\n\n        vector<vector<int>> valid_list(M);\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (usable_placement(k, p)) valid_list[t].push_back(p);\n            }\n            if (valid_list[t].empty()) return false;\n        }\n\n        vector<vector<int>> can_cover(M, vector<int>(D, 0));\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                for (int did : fields[k].ps[p].drill_ids) can_cover[t][did] = 1;\n            }\n        }\n\n        vector<vector<int>> rem_max(M + 1, vector<int>(D, 0));\n        for (int t = M - 1; t >= 0; --t) {\n            for (int d = 0; d < D; ++d) rem_max[t][d] = rem_max[t + 1][d] + can_cover[t][d];\n        }\n\n        array<short, MAXM> choice;\n        choice.fill(-1);\n        vector<int> cur(D, 0);\n\n        long long nodes = 0;\n        bool aborted = false;\n        int solutions = 0;\n        bool same_union = true;\n        bitset<MAXC> common_union;\n        bool has_common = false;\n\n        function<void(int)> dfs = [&](int t) {\n            if (aborted) return;\n            if (++nodes > 2000000LL || elapsed_ms() > 2870.0) {\n                aborted = true;\n                return;\n            }\n\n            for (int d = 0; d < D; ++d) {\n                if (cur[d] > drill_obs[d]) return;\n                if (cur[d] + rem_max[t][d] < drill_obs[d]) return;\n            }\n\n            if (t == M) {\n                for (int d = 0; d < D; ++d) if (cur[d] != drill_obs[d]) return;\n                solutions++;\n                bitset<MAXC> uni;\n                for (int kk = 0; kk < M; ++kk) {\n                    int p = choice[kk];\n                    uni |= fields[kk].ps[p].mask;\n                }\n                if (!has_common) {\n                    common_union = uni;\n                    has_common = true;\n                } else if (common_union != uni) {\n                    same_union = false;\n                }\n                return;\n            }\n\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                auto &pl = fields[k].ps[p];\n                choice[k] = (short)p;\n                for (int did : pl.drill_ids) cur[did]++;\n                dfs(t + 1);\n                for (int did : pl.drill_ids) cur[did]--;\n                if (aborted) return;\n            }\n        };\n\n        dfs(0);\n\n        if (aborted) return false;\n        if (solutions == 0) return false;\n        if (!same_union) return false;\n\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (common_union.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    bool confident_answer_from_top(const vector<SavedState>& top, vector<int>& ans_cells) {\n        if (top.empty()) return false;\n        if (top[0].exact_err != 0) return false;\n\n        vector<int> idxs;\n        for (int i = 0; i < (int)top.size(); ++i) {\n            if (top[i].exact_err == 0) idxs.push_back(i);\n        }\n        if ((int)idxs.size() < 4) return false;\n\n        int use = min(6, (int)idxs.size());\n        auto base = union_from_choice(top[idxs[0]].choice);\n        for (int t = 1; t < use; ++t) {\n            auto u = union_from_choice(top[idxs[t]].choice);\n            if (u != base) return false;\n        }\n\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (base[id]) ans_cells.push_back(id);\n        return true;\n    }\n\n    // ---------- drill selection ----------\n\n    int select_drill_cell_from_states(const vector<SavedState>& top) {\n        vector<double> best_score(C, -1e100);\n\n        // bonus near already positive drilled cells\n        vector<int> near_pos(C, 0);\n        for (int t = 0; t < (int)drill_cells.size(); ++t) {\n            if (drill_obs[t] <= 0) continue;\n            int id = drill_cells[t];\n            int x = id / N, y = id % N;\n            static const int dx[4] = {-1, 1, 0, 0};\n            static const int dy[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                    int nid = nx * N + ny;\n                    if (exact_v[nid] == -1) near_pos[nid]++;\n                }\n            }\n        }\n\n        // 1) use variance over top states if available\n        if (!top.empty()) {\n            int best_exact = top[0].exact_err;\n            vector<int> cand_idxs;\n            for (int i = 0; i < (int)top.size(); ++i) {\n                if (top[i].exact_err == best_exact) cand_idxs.push_back(i);\n            }\n            if ((int)cand_idxs.size() >= 2) {\n                int S = min(8, (int)cand_idxs.size());\n                vector<double> sum(C, 0.0), sq(C, 0.0), occ(C, 0.0);\n\n                for (int t = 0; t < S; ++t) {\n                    const auto& ch = top[cand_idxs[t]].choice;\n                    vector<int> cnt(C, 0);\n                    for (int k = 0; k < M; ++k) {\n                        int p = ch[k];\n                        if (p < 0) continue;\n                        for (int id : fields[k].ps[p].cells) cnt[id]++;\n                    }\n                    for (int id = 0; id < C; ++id) {\n                        if (exact_v[id] != -1) continue;\n                        sum[id] += cnt[id];\n                        sq[id] += 1.0 * cnt[id] * cnt[id];\n                        occ[id] += (cnt[id] > 0 ? 1.0 : 0.0);\n                    }\n                }\n\n                for (int id = 0; id < C; ++id) {\n                    if (exact_v[id] != -1) continue;\n                    double mean = sum[id] / S;\n                    double var = sq[id] / S - mean * mean;\n                    double pocc = occ[id] / S;\n                    double score = var + 0.30 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * mean;\n                    best_score[id] = max(best_score[id], score);\n                }\n            }\n        }\n\n        // 2) independent uncertainty from remaining valid placements\n        vector<double> pcover_sum(C, 0.0), var_sum(C, 0.0);\n        vector<int> cnt(C, 0);\n\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count <= 0) continue;\n            fill(cnt.begin(), cnt.end(), 0);\n            int tot = 0;\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                ++tot;\n                for (int id : fields[k].ps[p].cells) cnt[id]++;\n            }\n            if (tot == 0) continue;\n\n            for (int id = 0; id < C; ++id) {\n                if (exact_v[id] != -1) continue;\n                if (cnt[id] == 0) continue;\n                double pk = 1.0 * cnt[id] / tot;\n                pcover_sum[id] += pk;\n                var_sum[id] += pk * (1.0 - pk);\n            }\n        }\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1) continue;\n            // approx occupancy probability assuming independence\n            double p0 = 1.0;\n            for (int k = 0; k < M; ++k) {\n                if (fields[k].valid_count <= 0) continue;\n                int cov = 0;\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (usable_placement(k, p) && fields[k].ps[p].mask.test(id)) cov++;\n                }\n                if (fields[k].valid_count > 0) {\n                    double pk = 1.0 * cov / fields[k].valid_count;\n                    p0 *= (1.0 - pk);\n                }\n            }\n            double pocc = 1.0 - p0;\n            double score = var_sum[id] + 0.40 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * pcover_sum[id];\n            best_score[id] = max(best_score[id], score);\n        }\n\n        int best_cell = -1;\n        double best = -1e100;\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1) continue;\n            if (best_score[id] > best + 1e-12) {\n                best = best_score[id];\n                best_cell = id;\n            }\n        }\n\n        if (best_cell != -1) return best_cell;\n        for (int id = 0; id < C; ++id) if (exact_v[id] == -1) return id;\n        return -1;\n    }\n\n    // ---------- strategy ----------\n\n    bool should_use_search() const {\n        if (M <= 6) return true;\n        if (M <= 9 && Q >= 16) return true;\n        if (drill_cells.size() >= 4 && Q > 0 && M <= 12) return true;\n        return false;\n    }\n\n    bool heuristic_phase() {\n        int heuristic_limit;\n        if (M <= 4) heuristic_limit = 24;\n        else if (M <= 8) heuristic_limit = 18;\n        else if (M <= 12) heuristic_limit = 12;\n        else heuristic_limit = 8;\n\n        if (eps <= 0.05) heuristic_limit += 4;\n        heuristic_limit = min(28, heuristic_limit);\n\n        bool guessed_nonexact = false;\n\n        for (int step = 0; step < heuristic_limit; ++step) {\n            if (elapsed_ms() > 2800.0) break;\n\n            vector<int> ans_cells;\n\n            if (all_fields_unique(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            if (exact_deduce_union(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            vector<SavedState> top;\n            if (should_use_search()) {\n                int restarts = (step == 0 ? 18 : 8);\n                if (M <= 5) restarts += 8;\n                if (eps <= 0.05) restarts += 4;\n                top = search_states(restarts);\n\n                if (!guessed_nonexact && confident_answer_from_top(top, ans_cells)) {\n                    guessed_nonexact = true;\n                    if (ask_answer(ans_cells)) return true;\n                }\n            }\n\n            int cell = select_drill_cell_from_states(top);\n            if (cell == -1) break;\n\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n            propagate_constraints();\n        }\n\n        vector<int> ans_cells;\n        if (all_fields_unique(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        if (exact_deduce_union(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        return false;\n    }\n\n    void exhaustive_finish() {\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1) {\n                int v = ask_drill(id);\n                register_drill(id, v);\n            }\n        }\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        ask_answer(ans);\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_blocks();\n        build_query_sets();\n        if (Q > 0) ask_initial_queries();\n        enumerate_placements();\n\n        if (heuristic_phase()) return;\n        exhaustive_finish();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct RowSol {\n    int l, r, h;\n    vector<vector<int>> w;   // minimum widths [D][m]\n    vector<int> perm;        // left-to-right order of local indices\n    ll vcost;\n};\n\nstruct Solver {\n    int W, D, N;\n    vector<vector<int>> a;               // [D][N], sorted ascending in input\n    vector<vector<int>> minH;            // minimal feasible shelf height, -1 if impossible\n    vector<ll> quickCostCache;           // cache for quick row cost\n    vector<char> quickCostUsed;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> W >> D >> N;\n        a.assign(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\n        minH.assign(N, vector<int>(N, -1));\n\n        int SZ = N * N * (W + 1);\n        quickCostCache.assign(SZ, 0);\n        quickCostUsed.assign(SZ, 0);\n    }\n\n    static int divup(int x, int y) {\n        return (x + y - 1) / y;\n    }\n\n    inline int cache_id(int l, int r, int h) const {\n        return ((l * N + r) * (W + 1) + h);\n    }\n\n    static int symdiff_count_sorted(const vector<int>& A, const vector<int>& B) {\n        int i = 0, j = 0, inter = 0;\n        while (i < (int)A.size() && j < (int)B.size()) {\n            if (A[i] == B[j]) {\n                inter++;\n                i++; j++;\n            } else if (A[i] < B[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return (int)A.size() + (int)B.size() - 2 * inter;\n    }\n\n    bool feasible_seg(int l, int r, int h) const {\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int k = l; k <= r; k++) {\n                s += divup(a[d][k], h);\n                if (s > W) return false;\n            }\n        }\n        return true;\n    }\n\n    void precompute_min_heights() {\n        for (int l = 0; l < N; l++) {\n            for (int r = l; r < N; r++) {\n                if (!feasible_seg(l, r, W)) break; // larger r will also be impossible\n\n                int lo = 1, hi = W;\n                while (lo < hi) {\n                    int mid = (lo + hi) >> 1;\n                    if (feasible_seg(l, r, mid)) hi = mid;\n                    else lo = mid + 1;\n                }\n                minH[l][r] = lo;\n            }\n        }\n    }\n\n    // Quick row cost for a fixed segment [l, r] and shelf height h.\n    // We use natural order and make the row full width by giving all slack to the last rectangle.\n    // Internal cuts are therefore just the prefix sums of the minimum widths of the first m-1 rectangles.\n    ll quick_row_cost(int l, int r, int h) {\n        int id = cache_id(l, r, h);\n        if (quickCostUsed[id]) return quickCostCache[id];\n        quickCostUsed[id] = 1;\n\n        int m = r - l + 1;\n        vector<vector<int>> cuts(D);\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int k = l; k < r; k++) {\n                cur += divup(a[d][k], h);\n                cuts[d].push_back(cur);\n            }\n            // feasibility assumed by caller\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            int cnt = symdiff_count_sorted(cuts[d - 1], cuts[d]);\n            v += 1LL * h * cnt;\n        }\n        quickCostCache[id] = v;\n        return v;\n    }\n\n    // DP for partitioning reservation indices into consecutive shelves.\n    // Cost uses only min-height quick row cost + row penalty.\n    vector<pair<int,int>> partition_dp(int rowPenalty) {\n        vector<vector<ll>> dp(N + 1, vector<ll>(W + 1, INF64));\n        vector<vector<short>> parPos(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parH(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n        for (int pos = 0; pos < N; pos++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[pos][used] >= INF64 / 4) continue;\n                for (int r = pos; r < N; r++) {\n                    int h = minH[pos][r];\n                    if (h == -1) break;\n                    int nu = used + h;\n                    if (nu > W) continue;\n                    ll cand = dp[pos][used] + quick_row_cost(pos, r, h) + rowPenalty;\n                    if (cand < dp[r + 1][nu]) {\n                        dp[r + 1][nu] = cand;\n                        parPos[r + 1][nu] = (short)pos;\n                        parH[r + 1][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        ll best = INF64;\n        int bestH = -1;\n        for (int h = 0; h <= W; h++) {\n            if (dp[N][h] < best) {\n                best = dp[N][h];\n                bestH = h;\n            }\n        }\n        if (bestH == -1) return {};\n\n        vector<pair<int,int>> rev;\n        int curPos = N, curH = bestH;\n        while (curPos > 0) {\n            int p = parPos[curPos][curH];\n            int ph = parH[curPos][curH];\n            if (p < 0 || ph < 0) return {};\n            rev.push_back({p, curPos - 1});\n            curPos = p;\n            curH = ph;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    ll score_partition_minheight(const vector<pair<int,int>>& parts) {\n        if (parts.empty()) return INF64;\n        int usedH = 0;\n        ll cost = 0;\n        for (auto [l, r] : parts) {\n            int h = minH[l][r];\n            if (h == -1) return INF64;\n            usedH += h;\n            if (usedH > W) return INF64;\n            cost += quick_row_cost(l, r, h);\n        }\n        return cost;\n    }\n\n    // Local search on partition boundaries, using only min-height quick cost.\n    vector<pair<int,int>> improve_partition(vector<pair<int,int>> parts) {\n        ll cur = score_partition_minheight(parts);\n        if (cur >= INF64 / 4) return parts;\n\n        for (int round = 0; round < 15; round++) {\n            ll best = cur;\n            vector<pair<int,int>> bestParts = parts;\n            int G = (int)parts.size();\n\n            // Shift boundary by 1\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n\n                // move one item from left row to right row\n                if (l1 < r1) {\n                    vector<pair<int,int>> np = parts;\n                    np[i] = {l1, r1 - 1};\n                    np[i + 1] = {r1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n\n                // move one item from right row to left row\n                if (l2 < r2) {\n                    vector<pair<int,int>> np = parts;\n                    np[i] = {l1, l2};\n                    np[i + 1] = {l2 + 1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n            }\n\n            // Merge adjacent rows\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n                vector<pair<int,int>> np;\n                for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                np.push_back({l1, r2});\n                for (int j = i + 2; j < G; j++) np.push_back(parts[j]);\n                ll sc = score_partition_minheight(np);\n                if (sc < best) {\n                    best = sc;\n                    bestParts = np;\n                }\n            }\n\n            // Split a row\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                if (l == r) continue;\n                for (int c = l; c < r; c++) {\n                    vector<pair<int,int>> np;\n                    for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                    np.push_back({l, c});\n                    np.push_back({c + 1, r});\n                    for (int j = i + 1; j < G; j++) np.push_back(parts[j]);\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n            }\n\n            if (best >= cur) break;\n            cur = best;\n            parts = bestParts;\n        }\n        return parts;\n    }\n\n    // Allocate all leftover vertical height among shelves using quick row cost.\n    pair<ll, vector<int>> allocate_heights_quick(const vector<pair<int,int>>& parts) {\n        int G = (int)parts.size();\n        if (G == 0) return {INF64, {}};\n\n        vector<int> hmin(G);\n        int used = 0;\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            hmin[i] = minH[l][r];\n            if (hmin[i] == -1) return {INF64, {}};\n            used += hmin[i];\n        }\n        if (used > W) return {INF64, {}};\n\n        int slack = W - used;\n\n        vector<vector<ll>> addCost(G, vector<ll>(slack + 1, INF64));\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            for (int e = 0; e <= slack; e++) {\n                addCost[i][e] = quick_row_cost(l, r, hmin[i] + e);\n            }\n        }\n\n        vector<vector<ll>> dp(G + 1, vector<ll>(slack + 1, INF64));\n        vector<vector<short>> par(G + 1, vector<short>(slack + 1, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < G; i++) {\n            for (int usedE = 0; usedE <= slack; usedE++) {\n                if (dp[i][usedE] >= INF64 / 4) continue;\n                for (int e = 0; usedE + e <= slack; e++) {\n                    ll cand = dp[i][usedE] + addCost[i][e];\n                    if (cand < dp[i + 1][usedE + e]) {\n                        dp[i + 1][usedE + e] = cand;\n                        par[i + 1][usedE + e] = (short)e;\n                    }\n                }\n            }\n        }\n\n        if (dp[G][slack] >= INF64 / 4) return {INF64, {}};\n\n        vector<int> heights(G);\n        int rem = slack;\n        for (int i = G; i >= 1; i--) {\n            int e = par[i][rem];\n            heights[i - 1] = hmin[i - 1] + e;\n            rem -= e;\n        }\n        return {dp[G][slack], heights};\n    }\n\n    ll eval_perm_cost(const vector<vector<int>>& w, const vector<int>& perm, int h) const {\n        int m = (int)perm.size();\n        vector<vector<int>> cuts(D);\n\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int p = 0; p + 1 < m; p++) {\n                int t = perm[p];\n                cur += w[d][t];\n                cuts[d].push_back(cur);\n            }\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            int cnt = symdiff_count_sorted(cuts[d - 1], cuts[d]);\n            v += 1LL * h * cnt;\n        }\n        return v;\n    }\n\n    RowSol build_row_sol(int l, int r, int h) const {\n        RowSol row;\n        row.l = l;\n        row.r = r;\n        row.h = h;\n        int m = r - l + 1;\n        row.w.assign(D, vector<int>(m));\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < m; t++) {\n                int ww = divup(a[d][l + t], h);\n                row.w[d][t] = ww;\n                s += ww;\n            }\n            // feasible by construction of height allocation\n            (void)s;\n        }\n\n        vector<int> vol(m, 0), avgw(m, 0);\n        for (int t = 0; t < m; t++) {\n            for (int d = 1; d < D; d++) vol[t] += abs(row.w[d][t] - row.w[d - 1][t]);\n            for (int d = 0; d < D; d++) avgw[t] += row.w[d][t];\n        }\n\n        vector<vector<int>> init_orders;\n        auto add_unique = [&](const vector<int>& ord) {\n            for (auto& v : init_orders) if (v == ord) return;\n            init_orders.push_back(ord);\n        };\n\n        vector<int> id(m), rev(m), byVol(m), byAvg(m);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        byVol = id;\n        sort(byVol.begin(), byVol.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            return x < y;\n        });\n\n        byAvg = id;\n        sort(byAvg.begin(), byAvg.end(), [&](int x, int y) {\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            return x < y;\n        });\n\n        add_unique(id);\n        add_unique(rev);\n        add_unique(byVol);\n        reverse(byVol.begin(), byVol.end());\n        add_unique(byVol);\n        add_unique(byAvg);\n        reverse(byAvg.begin(), byAvg.end());\n        add_unique(byAvg);\n\n        ll bestCost = INF64;\n        vector<int> bestPerm = id;\n\n        auto improve = [&](vector<int> perm) -> pair<ll, vector<int>> {\n            ll cur = eval_perm_cost(row.w, perm, h);\n\n            for (int round = 0; round < 6; round++) {\n                ll best = cur;\n                int bi = -1, bj = -1;\n                for (int i = 0; i < m; i++) {\n                    for (int j = i + 1; j < m; j++) {\n                        swap(perm[i], perm[j]);\n                        ll sc = eval_perm_cost(row.w, perm, h);\n                        swap(perm[i], perm[j]);\n                        if (sc < best) {\n                            best = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(perm[bi], perm[bj]);\n                cur = best;\n            }\n\n            for (int round = 0; round < 3; round++) {\n                ll best = cur;\n                int bi = -1, bj = -1;\n                for (int i = 0; i < m; i++) {\n                    for (int j = 0; j < m; j++) if (i != j) {\n                        vector<int> np = perm;\n                        int v = np[i];\n                        np.erase(np.begin() + i);\n                        np.insert(np.begin() + j, v);\n                        ll sc = eval_perm_cost(row.w, np, h);\n                        if (sc < best) {\n                            best = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                int v = perm[bi];\n                perm.erase(perm.begin() + bi);\n                perm.insert(perm.begin() + bj, v);\n                cur = best;\n            }\n\n            return {cur, perm};\n        };\n\n        for (auto ord : init_orders) {\n            auto [sc, p] = improve(ord);\n            if (sc < bestCost) {\n                bestCost = sc;\n                bestPerm = p;\n            }\n        }\n\n        row.perm = bestPerm;\n        row.vcost = bestCost;\n        return row;\n    }\n\n    vector<vector<Rect>> fallback_answer() const {\n        vector<vector<Rect>> ans(D, vector<Rect>(N));\n        for (int d = 0; d < D; d++) {\n            vector<int> c(N, 1);\n            int rem = W - N;\n\n            while (rem > 0) {\n                int bestGain = 0, bestK = -1;\n                for (int k = 0; k < N; k++) {\n                    if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                    int deficit = a[d][k] - W * c[k];\n                    int gain = deficit > 0 ? min(W, deficit) : 0;\n                    if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                        bestGain = gain;\n                        bestK = k;\n                    }\n                }\n                if (bestGain <= 0) break;\n                c[bestK]++;\n                rem--;\n            }\n            c[N - 1] += rem;\n\n            vector<int> top(N), bot(N);\n            int cur = 0;\n            for (int k = 0; k < N; k++) {\n                top[k] = cur;\n                cur += c[k];\n                bot[k] = cur;\n            }\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            stable_sort(ord.begin(), ord.end(), [&](int x, int y) {\n                if (c[x] != c[y]) return c[x] < c[y];\n                return x < y;\n            });\n\n            for (int k = 0; k < N; k++) {\n                int idx = ord[k];\n                ans[d][k] = {top[idx], 0, bot[idx], W};\n            }\n        }\n        return ans;\n    }\n\n    bool validate_answer(const vector<vector<Rect>>& ans) const {\n        if ((int)ans.size() != D) return false;\n        for (int d = 0; d < D; d++) {\n            if ((int)ans[d].size() != N) return false;\n            for (int k = 0; k < N; k++) {\n                const auto& r = ans[d][k];\n                if (!(0 <= r.i0 && r.i0 < r.i1 && r.i1 <= W)) return false;\n                if (!(0 <= r.j0 && r.j0 < r.j1 && r.j1 <= W)) return false;\n            }\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    const auto& A = ans[d][i];\n                    const auto& B = ans[d][j];\n                    int h = min(A.i1, B.i1) - max(A.i0, B.i0);\n                    int w = min(A.j1, B.j1) - max(A.j0, B.j0);\n                    if (h > 0 && w > 0) return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    void solve() {\n        precompute_min_heights();\n\n        vector<vector<pair<int,int>>> candParts;\n\n        vector<int> penalties = {0, 200, 800, 3000, 10000};\n        for (int pen : penalties) {\n            auto p = partition_dp(pen);\n            if (p.empty()) continue;\n            p = improve_partition(p);\n\n            bool dup = false;\n            for (auto& q : candParts) if (q == p) dup = true;\n            if (!dup) candParts.push_back(p);\n        }\n\n        // Also try the one-row partition if feasible.\n        if (minH[0][N - 1] != -1) {\n            vector<pair<int,int>> p = {{0, N - 1}};\n            p = improve_partition(p);\n            bool dup = false;\n            for (auto& q : candParts) if (q == p) dup = true;\n            if (!dup) candParts.push_back(p);\n        }\n\n        vector<vector<Rect>> bestAns;\n        ll bestExact = INF64;\n\n        for (auto& parts : candParts) {\n            auto [quickScore, heights] = allocate_heights_quick(parts);\n            if (quickScore >= INF64 / 4) continue;\n\n            int G = (int)parts.size();\n            vector<RowSol> rows;\n            rows.reserve(G);\n            ll exactCost = 0;\n            bool ok = true;\n\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                int h = heights[i];\n                if (!feasible_seg(l, r, h)) {\n                    ok = false;\n                    break;\n                }\n                RowSol row = build_row_sol(l, r, h);\n                exactCost += row.vcost;\n                rows.push_back(std::move(row));\n            }\n            if (!ok) continue;\n\n            vector<vector<Rect>> ans(D, vector<Rect>(N));\n            int y = 0;\n            for (int i = 0; i < G; i++) {\n                const RowSol& row = rows[i];\n                int m = row.r - row.l + 1;\n                int y0 = y, y1 = y + row.h;\n                y = y1;\n\n                for (int d = 0; d < D; d++) {\n                    int sumMin = 0;\n                    for (int t = 0; t < m; t++) sumMin += row.w[d][t];\n                    int slackW = W - sumMin;\n                    int x = 0;\n                    for (int p = 0; p < m; p++) {\n                        int t = row.perm[p];\n                        int k = row.l + t;\n                        int ww = row.w[d][t] + (p + 1 == m ? slackW : 0);\n                        ans[d][k] = {y0, x, y1, x + ww};\n                        x += ww;\n                    }\n                    if (x != W) ok = false;\n                }\n            }\n            if (!ok || y != W) continue;\n            if (!validate_answer(ans)) continue;\n\n            if (exactCost < bestExact) {\n                bestExact = exactCost;\n                bestAns = std::move(ans);\n            }\n        }\n\n        if (bestAns.empty()) bestAns = fallback_answer();\n        if (!validate_answer(bestAns)) bestAns = fallback_answer();\n\n        for (int d = 0; d < D; d++) {\n            for (int k = 0; k < N; k++) {\n                const auto& r = bestAns[d][k];\n                cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 9;\nstatic constexpr int POS = 7;               // N - 2\nstatic constexpr int CELL = 81;\nstatic constexpr int MOD = 998244353;\nstatic constexpr int MAX_A = 20 * 7 * 7;    // 980\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 Action {\n    int m, p, q;\n    array<uint8_t, 9> cell;\n    array<int, 9> val;\n};\n\nstruct Solution {\n    array<int, CELL> r{};\n    array<uint8_t, MAX_A> cnt{};\n    vector<uint16_t> ops;\n    int L = 0;\n    long long score = 0;\n};\n\nstruct BestAdd {\n    long long gain = LLONG_MIN;\n    int id = -1;\n};\n\nstruct BestPair {\n    long long gain = LLONG_MIN;\n    int a = -1, b = -1;\n};\n\nstruct BestSwap {\n    long long gain = LLONG_MIN;\n    int rem = -1, add = -1;\n};\n\nint M_in, K_in;\narray<int, CELL> init_r;\nvector<Action> actions;\nint A = 0;\n\ninline long long gain_add(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_remove(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - oldv;\n    }\n    return delta;\n}\n\ninline long long gain_swap(const Solution& s, int rem_id, int add_id) {\n    if (rem_id == add_id) return 0;\n    const auto& rm = actions[rem_id];\n    const auto& ad = actions[add_id];\n\n    long long delta = 0;\n    bool used_ad[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = rm.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv - rm.val[i];\n        if (nv < 0) nv += MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (ad.cell[j] == idx) {\n                nv += ad.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_ad[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_ad[j]) {\n            int idx = ad.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + ad.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline long long gain_add_pair(const Solution& s, int a_id, int b_id) {\n    const auto& a = actions[a_id];\n    const auto& b = actions[b_id];\n\n    long long delta = 0;\n    bool used_b[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = a.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv + a.val[i];\n        if (nv >= MOD) nv -= MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (b.cell[j] == idx) {\n                nv += b.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_b[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_b[j]) {\n            int idx = b.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + b.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline void apply_add(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    ++s.cnt[aid];\n    s.ops.push_back((uint16_t)aid);\n    ++s.L;\n}\n\ninline void apply_remove_aid(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n\n    for (int i = (int)s.ops.size() - 1; i >= 0; --i) {\n        if ((int)s.ops[i] == aid) {\n            s.ops[i] = s.ops.back();\n            s.ops.pop_back();\n            return;\n        }\n    }\n}\n\ninline void apply_remove_index(Solution& s, int idx_in_ops) {\n    int aid = s.ops[idx_in_ops];\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n    s.ops[idx_in_ops] = s.ops.back();\n    s.ops.pop_back();\n}\n\nSolution make_base_solution() {\n    Solution s;\n    s.r = init_r;\n    s.cnt.fill(0);\n    s.ops.clear();\n    s.ops.reserve(K_in);\n    s.L = 0;\n    s.score = 0;\n    for (int i = 0; i < CELL; ++i) s.score += s.r[i];\n    return s;\n}\n\nBestAdd best_single_add(const Solution& s) {\n    BestAdd res;\n    res.gain = 0;\n    res.id = -1;\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = gain_add(s, aid);\n        if (g > res.gain) {\n            res.gain = g;\n            res.id = aid;\n        }\n    }\n    return res;\n}\n\nvector<pair<long long, int>> top_adds(const Solution& s, int T, bool positive_only = false) {\n    vector<pair<long long, int>> v;\n    v.reserve(A);\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = gain_add(s, aid);\n        if (!positive_only || g > 0) v.push_back({g, aid});\n    }\n    if (v.empty()) return v;\n    if ((int)v.size() > T) {\n        nth_element(v.begin(), v.begin() + T, v.end(),\n                    [](const auto& x, const auto& y) { return x.first > y.first; });\n        v.resize(T);\n    }\n    sort(v.begin(), v.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    return v;\n}\n\nBestPair best_pair_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestPair res;\n    res.gain = 0;\n    res.a = res.b = -1;\n    int T = (int)cand.size();\n    for (int i = 0; i < T; ++i) {\n        int a = cand[i].second;\n        for (int j = i; j < T; ++j) {\n            int b = cand[j].second;\n            long long g = gain_add_pair(s, a, b);\n            if (g > res.gain) {\n                res.gain = g;\n                res.a = a;\n                res.b = b;\n            }\n        }\n    }\n    return res;\n}\n\nBestSwap best_swap_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestSwap res;\n    res.gain = 0;\n    res.rem = res.add = -1;\n\n    vector<int> used_ids;\n    used_ids.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (s.cnt[aid]) used_ids.push_back(aid);\n    }\n\n    for (int rem : used_ids) {\n        for (auto [g0, add] : cand) {\n            (void)g0;\n            if (add == rem) continue;\n            long long g = gain_swap(s, rem, add);\n            if (g > res.gain) {\n                res.gain = g;\n                res.rem = rem;\n                res.add = add;\n            }\n        }\n    }\n    return res;\n}\n\ntemplate <class RNG>\nvoid randomized_fill(Solution& s, RNG& rng, int topT = 12) {\n    while (s.L < K_in) {\n        auto cand = top_adds(s, topT, true);\n        if (cand.empty() || cand[0].first <= 0) break;\n        int t = min<int>(8, cand.size());\n        int total_w = t * (t + 1) / 2;\n        int r = (int)(rng() % total_w);\n        int acc = 0;\n        int pick = cand[0].second;\n        for (int i = 0; i < t; ++i) {\n            acc += (t - i);\n            if (r < acc) {\n                pick = cand[i].second;\n                break;\n            }\n        }\n        apply_add(s, pick);\n    }\n}\n\ntemplate <class RNG>\nSolution build_greedy(bool randomized, RNG& rng) {\n    Solution s = make_base_solution();\n\n    if (!randomized) {\n        while (s.L < K_in) {\n            auto best = best_single_add(s);\n            if (best.gain <= 0) break;\n            apply_add(s, best.id);\n        }\n    } else {\n        randomized_fill(s, rng, 16);\n    }\n\n    return s;\n}\n\nvoid local_improve(Solution& s, const Timer& timer, double deadline, int max_rounds = 12) {\n    const int TOP_PAIR = 120;\n    const int TOP_SWAP = 240;\n\n    for (int round = 0; round < max_rounds && timer.elapsed() < deadline; ++round) {\n        bool changed = false;\n\n        // Repeated best positive single-add\n        while (s.L < K_in && timer.elapsed() < deadline) {\n            auto best = best_single_add(s);\n            if (best.gain <= 0) break;\n            apply_add(s, best.id);\n            changed = true;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        // Positive pair-add\n        if (s.L <= K_in - 2) {\n            auto cand = top_adds(s, TOP_PAIR, false);\n            auto bp = best_pair_from_candidates(s, cand);\n            if (bp.gain > 0) {\n                apply_add(s, bp.a);\n                apply_add(s, bp.b);\n                changed = true;\n                continue;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        // Swap\n        if (s.L > 0) {\n            auto cand = top_adds(s, TOP_SWAP, false);\n            auto bs = best_swap_from_candidates(s, cand);\n            if (bs.gain > 0) {\n                apply_remove_aid(s, bs.rem);\n                apply_add(s, bs.add);\n                changed = true;\n                continue;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\ntemplate <class RNG>\nSolution perturb_and_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 16);\n        local_improve(s, timer, deadline, 6);\n        return s;\n    }\n\n    int R = 2 + (int)(rng() % 4); // 2..5\n    R = min(R, s.L);\n\n    vector<pair<long long, int>> rems;\n    rems.reserve(s.L);\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        int aid = s.ops[i];\n        long long gr = gain_remove(s, aid);\n        rems.push_back({gr, i});\n    }\n\n    sort(rems.begin(), rems.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first; // better removal first\n        return x.second < y.second;\n    });\n\n    int pool = min<int>(12, rems.size());\n    vector<int> pick_idx;\n    pick_idx.reserve(R);\n    vector<int> pool_ids(pool);\n    iota(pool_ids.begin(), pool_ids.end(), 0);\n\n    for (int t = 0; t < R && !pool_ids.empty(); ++t) {\n        int lim = min<int>(6, pool_ids.size());\n        int total_w = lim * (lim + 1) / 2;\n        int rr = (int)(rng() % total_w);\n        int acc = 0, choose_pos = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (lim - i);\n            if (rr < acc) {\n                choose_pos = i;\n                break;\n            }\n        }\n        int sel = pool_ids[choose_pos];\n        pick_idx.push_back(rems[sel].second);\n        pool_ids.erase(pool_ids.begin() + choose_pos);\n    }\n\n    sort(pick_idx.begin(), pick_idx.end(), greater<int>());\n    for (int idx : pick_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 16);\n    local_improve(s, timer, deadline, 8);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_in;\n    cin >> N_in >> M_in >> K_in;\n\n    for (int i = 0; i < N_in; ++i) {\n        for (int j = 0; j < N_in; ++j) {\n            cin >> init_r[i * N + j];\n        }\n    }\n\n    vector<array<array<int, 3>, 3>> stamps(M_in);\n    for (int m = 0; m < M_in; ++m) {\n        for (int i = 0; i < 3; ++i) {\n            for (int j = 0; j < 3; ++j) {\n                cin >> stamps[m][i][j];\n            }\n        }\n    }\n\n    actions.clear();\n    actions.reserve(M_in * POS * POS);\n    for (int m = 0; m < M_in; ++m) {\n        for (int p = 0; p <= N_in - 3; ++p) {\n            for (int q = 0; q <= N_in - 3; ++q) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                int t = 0;\n                for (int i = 0; i < 3; ++i) {\n                    for (int j = 0; j < 3; ++j) {\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.val[t] = stamps[m][i][j];\n                        ++t;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n    A = (int)actions.size();\n\n    Timer timer;\n    const double TIME_LIMIT = 1.92;\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count() ^\n        (uint64_t)(uintptr_t)new int\n    );\n\n    Solution best = build_greedy(false, rng);\n    local_improve(best, timer, TIME_LIMIT, 16);\n\n    Solution current = best;\n\n    // A few randomized starts\n    while (timer.elapsed() < 0.35 && timer.elapsed() < TIME_LIMIT) {\n        Solution s = build_greedy(true, rng);\n        local_improve(s, timer, TIME_LIMIT, 10);\n        if (s.score > best.score) {\n            best = s;\n            current = s;\n        }\n    }\n\n    // Iterated local search with SA-like acceptance\n    while (timer.elapsed() < TIME_LIMIT) {\n        Solution base;\n        uint64_t rv = rng() % 100;\n        if (rv < 15) {\n            base = build_greedy(true, rng);\n            local_improve(base, timer, TIME_LIMIT, 6);\n        } else if (rv < 55) {\n            base = best;\n        } else {\n            base = current;\n        }\n\n        Solution cand = perturb_and_rebuild(base, rng, timer, TIME_LIMIT);\n\n        if (cand.score > best.score) best = cand;\n\n        double progress = min(1.0, timer.elapsed() / TIME_LIMIT);\n        long double T0 = 2.0e8L;\n        long double T1 = 1.0e6L;\n        long double temp = T0 * pow(T1 / T0, progress);\n\n        long long diff = cand.score - current.score;\n        bool accept = false;\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            long double prob = expl((long double)diff / temp);\n            long double u = (long double)(rng() >> 11) * (1.0L / (1ULL << 53));\n            if (u < prob) accept = true;\n        }\n\n        if (accept) current = cand;\n        if (current.score > best.score) best = current;\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (int aid : best.ops) {\n        const auto& ac = actions[aid];\n        cout << ac.m << ' ' << ac.p << ' ' << ac.q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int TOTAL = 25;\nstatic constexpr int INF = 1e9;\n\nstruct Pos {\n    int r, c;\n};\n\nstatic int mdist(const Pos& a, const Pos& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\n\nstatic vector<char> make_route(Pos cur, Pos dst) {\n    vector<char> res;\n    while (cur.r < dst.r) res.push_back('D'), cur.r++;\n    while (cur.r > dst.r) res.push_back('U'), cur.r--;\n    while (cur.c < dst.c) res.push_back('R'), cur.c++;\n    while (cur.c > dst.c) res.push_back('L'), cur.c--;\n    return res;\n}\n\nstatic string macros_to_plan(const vector<pair<Pos, Pos>>& macros) {\n    string s;\n    Pos cur{0, 0};\n    for (auto [src, dst] : macros) {\n        auto p1 = make_route(cur, src);\n        for (char ch : p1) s.push_back(ch);\n        s.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) s.push_back(ch);\n        s.push_back('Q');\n        cur = dst;\n    }\n    if (s.empty()) s = \".\";\n    return s;\n}\n\n// ============================================================\n// Simulator / evaluator\n// ============================================================\n\nstruct EvaluationResult {\n    bool legal = false;\n    long long score = (1LL << 60);\n};\n\nstruct Simulator {\n    int A[N][N];\n\n    struct Crane {\n        int r, c;\n        int hold;   // -1 if none\n        bool alive;\n        bool large;\n    };\n\n    Simulator(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n    }\n\n    EvaluationResult evaluate(const vector<string>& S) const {\n        int board[N][N];\n        int spawn_ptr[N];\n        bool dispatched[TOTAL];\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n\n        Crane cranes[N];\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n\n        int T = 0;\n        for (auto &s : S) T = max(T, (int)s.size());\n        if (T < 1 || T > 10000) return {};\n\n        vector<int> out_seq[N];\n\n        auto step_spawn = [&]() {\n            for (int r = 0; r < N; r++) {\n                if (spawn_ptr[r] >= N) continue;\n                if (board[r][0] != -1) continue;\n\n                bool blocked_by_holding_crane = false;\n                for (int i = 0; i < N; i++) {\n                    if (!cranes[i].alive) continue;\n                    if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                        blocked_by_holding_crane = true;\n                        break;\n                    }\n                }\n                if (blocked_by_holding_crane) continue;\n\n                board[r][0] = A[r][spawn_ptr[r]];\n                spawn_ptr[r]++;\n            }\n        };\n\n        for (int turn = 0; turn < T; turn++) {\n            step_spawn();\n\n            array<char, N> act;\n            for (int i = 0; i < N; i++) {\n                act[i] = (turn < (int)S[i].size() ? S[i][turn] : '.');\n            }\n\n            array<int, N> nr, nc;\n            array<bool, N> final_alive;\n            array<bool, N> moving;\n            for (int i = 0; i < N; i++) {\n                nr[i] = cranes[i].r;\n                nc[i] = cranes[i].c;\n                final_alive[i] = cranes[i].alive;\n                moving[i] = false;\n            }\n\n            // local legality + intended destinations\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) {\n                    if (act[i] != '.') return {};\n                    continue;\n                }\n\n                char a = act[i];\n                if (a == 'U') nr[i]--, moving[i] = true;\n                else if (a == 'D') nr[i]++, moving[i] = true;\n                else if (a == 'L') nc[i]--, moving[i] = true;\n                else if (a == 'R') nc[i]++, moving[i] = true;\n\n                if (a == 'U' || a == 'D' || a == 'L' || a == 'R') {\n                    if (nr[i] < 0 || nr[i] >= N || nc[i] < 0 || nc[i] >= N) return {};\n                    if (!cranes[i].large && cranes[i].hold != -1 && board[nr[i]][nc[i]] != -1) return {};\n                } else if (a == 'P') {\n                    if (cranes[i].hold != -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] == -1) return {};\n                } else if (a == 'Q') {\n                    if (cranes[i].hold == -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] != -1) return {};\n                } else if (a == 'B') {\n                    if (cranes[i].hold != -1) return {};\n                    final_alive[i] = false;\n                } else if (a == '.') {\n                } else {\n                    return {};\n                }\n            }\n\n            // final-cell collision:\n            // cranes that bomb do not occupy final cells\n            for (int i = 0; i < N; i++) if (final_alive[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j]) {\n                    if (nr[i] == nr[j] && nc[i] == nc[j]) return {};\n                }\n            }\n\n            // passing (swap) check only among cranes that remain alive and both move\n            for (int i = 0; i < N; i++) if (final_alive[i] && moving[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j] && moving[j]) {\n                    if (nr[i] == cranes[j].r && nc[i] == cranes[j].c &&\n                        nr[j] == cranes[i].r && nc[j] == cranes[i].c) {\n                        return {};\n                    }\n                }\n            }\n\n            // apply\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n\n                char a = act[i];\n                if (a == '.') {\n                } else if (a == 'B') {\n                    cranes[i].alive = false;\n                } else if (a == 'P') {\n                    cranes[i].hold = board[cranes[i].r][cranes[i].c];\n                    board[cranes[i].r][cranes[i].c] = -1;\n                } else if (a == 'Q') {\n                    board[cranes[i].r][cranes[i].c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                } else {\n                    cranes[i].r = nr[i];\n                    cranes[i].c = nc[i];\n                }\n            }\n\n            // dispatch\n            for (int r = 0; r < N; r++) {\n                if (board[r][4] != -1) {\n                    int b = board[r][4];\n                    board[r][4] = -1;\n                    if (b < 0 || b >= TOTAL) return {};\n                    if (dispatched[b]) return {};\n                    dispatched[b] = true;\n                    out_seq[r].push_back(b);\n                }\n            }\n        }\n\n        int M0 = T;\n        int M1 = 0, M2 = 0;\n        int dispatched_count = 0;\n\n        for (int r = 0; r < N; r++) {\n            vector<int> correct;\n            for (int b : out_seq[r]) {\n                dispatched_count++;\n                if (b / 5 != r) M2++;\n                else correct.push_back(b);\n            }\n            for (int i = 0; i < (int)correct.size(); i++) {\n                for (int j = i + 1; j < (int)correct.size(); j++) {\n                    if (correct[i] > correct[j]) M1++;\n                }\n            }\n        }\n\n        int M3 = TOTAL - dispatched_count;\n        long long score = 1LL * M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n        return {true, score};\n    }\n};\n\n// ============================================================\n// Exact macro A* solver (optional candidate)\n// ============================================================\n\nstruct ExactSolver {\n    int A[N][N];\n    array<Pos, 15> cells; // buffer columns 1..3\n\n    ExactSolver(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        int idx = 0;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) {\n                cells[idx++] = {r, c};\n            }\n        }\n    }\n\n    struct Key {\n        uint64_t lo, hi;\n        bool operator==(const Key& o) const { return lo == o.lo && hi == o.hi; }\n    };\n    struct KeyHash {\n        size_t operator()(const Key& k) const {\n            uint64_t x = k.lo * 1000003ULL ^ (k.hi + 0x9e3779b97f4a7c15ULL + (k.lo << 6) + (k.lo >> 2));\n            return (size_t)x;\n        }\n    };\n\n    struct Action {\n        Pos src, dst;\n    };\n\n    struct State {\n        array<uint8_t, 5> ptr{};\n        array<uint8_t, 5> done{};\n        array<int8_t, 15> cell{};\n        uint8_t pos = 0;\n        int g = INF;\n        int parent = -1;\n        Action act;\n    };\n\n    static int pos_to_idx(const Pos& p) { return p.r * 5 + p.c; }\n    static Pos idx_to_pos(int idx) { return Pos{idx / 5, idx % 5}; }\n\n    Key pack(const State& s) const {\n        __uint128_t x = 0;\n        int sh = 0;\n        auto add = [&](uint64_t v, int bits) {\n            x |= ((__uint128_t)v) << sh;\n            sh += bits;\n        };\n        for (int i = 0; i < 5; i++) add(s.ptr[i], 3);\n        for (int i = 0; i < 5; i++) add(s.done[i], 3);\n        add(s.pos, 5);\n        for (int i = 0; i < 15; i++) add((s.cell[i] == -1 ? 31 : s.cell[i]), 5);\n        return {(uint64_t)x, (uint64_t)(x >> 64)};\n    }\n\n    int current_need(const State& s, int tr) const {\n        return 5 * tr + s.done[tr];\n    }\n\n    int heuristic(const State& s) const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int k = s.ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        for (int i = 0; i < 15; i++) {\n            int b = s.cell[i];\n            if (b == -1) continue;\n            int tr = b / 5;\n            h += 2 + abs(cells[i].r - tr) + (4 - cells[i].c);\n        }\n        return h;\n    }\n\n    bool finished(const State& s) const {\n        for (int i = 0; i < 5; i++) if (s.done[i] != 5) return false;\n        return true;\n    }\n\n    void enumerate_dispatches(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= 5) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.ptr[r]++;\n            t.done[tr]++;\n            Pos src{r, 0}, dst{tr, 4};\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n\n        for (int i = 0; i < 15; i++) {\n            int b = s.cell[i];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.cell[i] = -1;\n            t.done[tr]++;\n            Pos src = cells[i], dst{tr, 4};\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n    }\n\n    void enumerate_stores(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        vector<int> empties;\n        for (int i = 0; i < 15; i++) if (s.cell[i] == -1) empties.push_back(i);\n        if (empties.empty()) return;\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= 5) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b == current_need(s, tr)) continue;\n\n            vector<pair<tuple<int,int,int>, int>> cand;\n            for (int idx : empties) {\n                int local = mdist(Pos{r, 0}, cells[idx]) + mdist(cells[idx], Pos{tr, 4});\n                int rowmis = abs(cells[idx].r - tr);\n                int colpref = -cells[idx].c;\n                cand.push_back({{local, rowmis, colpref}, idx});\n            }\n            sort(cand.begin(), cand.end());\n\n            int K = min<int>(6, cand.size());\n            for (int z = 0; z < K; z++) {\n                int idx = cand[z].second;\n                State t = s;\n                t.ptr[r]++;\n                t.cell[idx] = b;\n                Pos src{r, 0}, dst = cells[idx];\n                t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n                t.pos = pos_to_idx(dst);\n                t.act = {src, dst};\n                nxt.push_back(t);\n            }\n        }\n    }\n\n    optional<string> solve_exact(double time_limit_ms = 600.0, int state_limit = 250000) {\n        auto start = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 15; i++) init.cell[i] = -1;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        struct PQNode {\n            int f, g, id;\n            bool operator<(const PQNode& o) const {\n                if (f != o.f) return f > o.f;\n                return g > o.g;\n            }\n        };\n\n        vector<State> states;\n        states.reserve(state_limit + 1000);\n        states.push_back(init);\n\n        unordered_map<Key, int, KeyHash> best;\n        best.reserve(state_limit * 2);\n        best[pack(init)] = 0;\n\n        priority_queue<PQNode> pq;\n        pq.push({heuristic(init), 0, 0});\n\n        while (!pq.empty() && (int)states.size() < state_limit && elapsed_ms() < time_limit_ms) {\n            auto [f, g, id] = pq.top();\n            pq.pop();\n            if (states[id].g != g) continue;\n            const State& s = states[id];\n\n            if (finished(s)) {\n                vector<pair<Pos, Pos>> macros;\n                int cur = id;\n                while (states[cur].parent != -1) {\n                    macros.push_back({states[cur].act.src, states[cur].act.dst});\n                    cur = states[cur].parent;\n                }\n                reverse(macros.begin(), macros.end());\n                return macros_to_plan(macros);\n            }\n\n            vector<State> nxt;\n            nxt.reserve(64);\n            enumerate_dispatches(s, nxt);\n            enumerate_stores(s, nxt);\n\n            for (State &t : nxt) {\n                t.parent = id;\n                Key k = pack(t);\n                auto it = best.find(k);\n                if (it != best.end()) {\n                    int oid = it->second;\n                    if (states[oid].g <= t.g) continue;\n                    it->second = (int)states.size();\n                } else {\n                    best.emplace(k, (int)states.size());\n                }\n                int h = heuristic(t);\n                states.push_back(t);\n                pq.push({t.g + h, t.g, (int)states.size() - 1});\n            }\n        }\n\n        return nullopt;\n    }\n};\n\n// ============================================================\n// Greedy portfolio\n// ============================================================\n\nstruct GreedyParam {\n    int dispatch_mode = 0;\n    int store_mode = 0;\n    int unlock_bonus = 0;\n};\n\nstruct GreedySolver {\n    int A[N][N];\n    GreedyParam param;\n\n    int board[N][N];\n    int spawn_ptr[N];\n    bool dispatched[TOTAL];\n    int total_dispatched = 0;\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    } cranes[N];\n\n    string out[N];\n    deque<char> plan;\n\n    GreedySolver(int A_[N][N], GreedyParam p) : param(p) {\n        memcpy(A, A_, sizeof(A));\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n    }\n\n    int current_need(int tr) const {\n        for (int x = 5 * tr; x < 5 * tr + 5; x++) {\n            if (!dispatched[x]) return x;\n        }\n        return 5 * tr + 5;\n    }\n\n    int inversion_increase_if_dispatch_now(int b) const {\n        int tr = b / 5;\n        int cnt = 0;\n        for (int x = 5 * tr; x < b; x++) {\n            if (!dispatched[x]) cnt++;\n        }\n        return cnt;\n    }\n\n    int remaining_lb() const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= 3; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + (4 - c);\n            }\n        }\n        for (int r = 0; r < N; r++) {\n            for (int k = spawn_ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        return h;\n    }\n\n    deque<char> make_transport_plan(Pos src, Pos dst) const {\n        deque<char> q;\n        auto p1 = make_route(Pos{cranes[0].r, cranes[0].c}, src);\n        for (char ch : p1) q.push_back(ch);\n        q.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) q.push_back(ch);\n        q.push_back('Q');\n        return q;\n    }\n\n    bool is_buffer_cell_empty(int r, int c) const {\n        if (c == 4) return false;\n        if (board[r][c] != -1) return false;\n        if (1 <= c && c <= 3) return true;\n        if (c == 0 && spawn_ptr[r] == N) return true;\n        return false;\n    }\n\n    vector<Pos> available_buffer_cells() const {\n        vector<Pos> v;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) {\n                if (is_buffer_cell_empty(r, c)) v.push_back({r, c});\n            }\n            if (is_buffer_cell_empty(r, 0)) v.push_back({r, 0});\n        }\n        return v;\n    }\n\n    int next_need_gap_after_storing_row(int r) const {\n        for (int k = spawn_ptr[r]; k < N; k++) {\n            int b = A[r][k];\n            int tr = b / 5;\n            if (!dispatched[b] && b == current_need(tr)) {\n                return k - spawn_ptr[r];\n            }\n        }\n        return INF;\n    }\n\n    struct Cand {\n        long long k1 = (1LL << 60), k2 = (1LL << 60), k3 = (1LL << 60);\n        Pos src{-1, -1}, dst{-1, -1};\n        bool ok = false;\n    };\n\n    optional<deque<char>> choose_dispatch_plan() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                if (b != current_need(tr)) continue;\n\n                Pos src{r, c}, dst{tr, 4};\n                int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n                int after_h = base_h - (2 + abs(r - tr) + (4 - c));\n\n                long long k1, k2, k3;\n                if (param.dispatch_mode == 0) {\n                    k1 = immediate;\n                    k2 = (c == 0 ? 0 : 1);\n                    k3 = after_h;\n                } else if (param.dispatch_mode == 1) {\n                    k1 = immediate + after_h;\n                    k2 = immediate;\n                    k3 = (c == 0 ? 0 : 1);\n                } else if (param.dispatch_mode == 2) {\n                    k1 = immediate + after_h - (c == 0 ? 3 : 0);\n                    k2 = immediate;\n                    k3 = after_h;\n                } else {\n                    k1 = abs(cur.r - r);\n                    k2 = immediate;\n                    k3 = after_h;\n                }\n\n                if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                    best = {k1, k2, k3, src, dst, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_store_plan() const {\n        auto buf = available_buffer_cells();\n        if (buf.empty()) return nullopt;\n\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) {\n            if (board[r][0] == -1) continue;\n            if (spawn_ptr[r] == N) continue;\n\n            int b = board[r][0];\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n\n            int gap = next_need_gap_after_storing_row(r);\n            int unlock = (gap >= INF ? 0 : max(0, 5 - gap));\n            int old_cost = 2 + abs(r - tr) + 4;\n\n            for (auto d : buf) {\n                int new_cost = 2 + abs(d.r - tr) + (4 - d.c);\n                int immediate = mdist(cur, Pos{r, 0}) + 1 + mdist(Pos{r, 0}, d) + 1;\n                int after_h = base_h - old_cost + new_cost;\n\n                long long k1, k2, k3;\n                if (param.store_mode == 0) {\n                    k1 = gap;\n                    k2 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k3 = new_cost;\n                } else if (param.store_mode == 1) {\n                    k1 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k2 = gap;\n                    k3 = new_cost;\n                } else if (param.store_mode == 2) {\n                    k1 = immediate;\n                    k2 = gap;\n                    k3 = after_h;\n                } else {\n                    k1 = new_cost;\n                    k2 = gap;\n                    k3 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                }\n\n                if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                    best = {k1, k2, k3, Pos{r, 0}, d, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_forced_early_dispatch() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                if (b == current_need(tr)) continue;\n\n                int inv = inversion_increase_if_dispatch_now(b);\n                Pos src{r, c}, dst{tr, 4};\n                int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n\n                long long k1 = inv;\n                long long k2 = immediate;\n                long long k3 = (c == 0 ? 0 : 1);\n\n                if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                    best = {k1, k2, k3, src, dst, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    deque<char> choose_next_plan() const {\n        if (auto p = choose_dispatch_plan()) return *p;\n        if (auto p = choose_store_plan()) return *p;\n        if (auto p = choose_forced_early_dispatch()) return *p;\n        return {};\n    }\n\n    void step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (blocked) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n    }\n\n    void apply_action(int idx, char act) {\n        auto &cr = cranes[idx];\n        if (!cr.alive) return;\n        if (act == '.') return;\n        if (act == 'B') {\n            cr.alive = false;\n            return;\n        }\n        if (act == 'P') {\n            cr.hold = board[cr.r][cr.c];\n            board[cr.r][cr.c] = -1;\n            return;\n        }\n        if (act == 'Q') {\n            board[cr.r][cr.c] = cr.hold;\n            cr.hold = -1;\n            return;\n        }\n        if (act == 'U') cr.r--;\n        if (act == 'D') cr.r++;\n        if (act == 'L') cr.c--;\n        if (act == 'R') cr.c++;\n    }\n\n    void step_dispatch() {\n        for (int r = 0; r < N; r++) {\n            if (board[r][4] != -1) {\n                int b = board[r][4];\n                board[r][4] = -1;\n                if (!dispatched[b]) {\n                    dispatched[b] = true;\n                    total_dispatched++;\n                }\n            }\n        }\n    }\n\n    vector<string> solve() {\n        int turn = 0;\n        while (total_dispatched < TOTAL && turn < 10000) {\n            step_spawn();\n\n            array<char, N> act;\n            act.fill('.');\n\n            if (turn == 0) {\n                for (int i = 1; i < N; i++) act[i] = 'B';\n            }\n\n            if (plan.empty()) plan = choose_next_plan();\n            if (!plan.empty()) {\n                act[0] = plan.front();\n                plan.pop_front();\n            }\n\n            for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n            for (int i = 0; i < N; i++) apply_action(i, act[i]);\n            step_dispatch();\n            turn++;\n        }\n\n        vector<string> res(N);\n        for (int i = 0; i < N; i++) res[i] = out[i];\n        if (res[0].empty()) res[0] = \".\";\n        for (int i = 1; i < N; i++) if (res[i].empty()) res[i] = \"B\";\n        return res;\n    }\n};\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n        }\n    }\n\n    Simulator sim(A);\n\n    vector<vector<string>> candidates;\n    vector<string> baseline_candidate;\n\n    // Greedy portfolio first: keep the first one as safe fallback\n    vector<GreedyParam> params = {\n        {0, 0, 4},\n        {1, 0, 5},\n        {1, 1, 6},\n        {2, 1, 4},\n        {0, 2, 3},\n        {3, 3, 5},\n        {2, 0, 5},\n        {1, 3, 4},\n    };\n\n    for (int idx = 0; idx < (int)params.size(); idx++) {\n        GreedySolver gs(A, params[idx]);\n        auto cand = gs.solve();\n        if (idx == 0) baseline_candidate = cand;\n        candidates.push_back(cand);\n    }\n\n    // Optional exact candidate\n    {\n        ExactSolver ex(A);\n        auto plan = ex.solve_exact(600.0, 250000);\n        if (plan.has_value()) {\n            vector<string> S(N);\n            S[0] = *plan;\n            for (int i = 1; i < N; i++) S[i] = \"B\";\n            candidates.push_back(S);\n        }\n    }\n\n    long long best_score = (1LL << 60);\n    vector<string> best_ans;\n\n    for (auto &cand : candidates) {\n        auto ev = sim.evaluate(cand);\n        if (!ev.legal) continue;\n        if (ev.score < best_score) {\n            best_score = ev.score;\n            best_ans = cand;\n        }\n    }\n\n    // Never fall back to idle.\n    if (best_ans.empty()) best_ans = baseline_candidate;\n\n    for (int i = 0; i < N; i++) {\n        cout << best_ans[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Solver {\n    int N, M;\n    vector<int> val;      // flattened heights\n    vector<int> nz_ids;   // non-zero cells\n    vector<int> pos_ids;  // positive cells\n\n    // Best global answer\n    ll best_var = INF64;\n    int best_kind = -1;   // 0 = circular order, 1 = tree\n    vector<int> best_circle;\n    int best_start = 0;\n\n    struct TreePlan {\n        int root = -1;\n        int orient = 0;\n        vector<vector<int>> children;\n        vector<int> parent, sum, sz;\n        ll var_cost = INF64;\n    } best_tree;\n\n    // Seed pool for local search\n    vector<pair<ll, vector<int>>> seed_pool;\n    unordered_set<uint64_t> seed_hashes;\n\n    // output\n    vector<string> ans;\n    int cur_r = 0, cur_c = 0;\n    ll truck = 0;\n\n    Solver(int N_, const vector<vector<int>>& h) : N(N_) {\n        M = N * N;\n        val.assign(M, 0);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                val[v] = h[r][c];\n                if (val[v] != 0) nz_ids.push_back(v);\n                if (val[v] > 0) pos_ids.push_back(v);\n            }\n        }\n    }\n\n    int id(int r, int c) const { return r * N + c; }\n    pair<int,int> rc(int v) const { return {v / N, v % N}; }\n\n    int dist0(int v) const {\n        auto [r, c] = rc(v);\n        return r + c;\n    }\n\n    int dist(int a, int b) const {\n        auto [ra, ca] = rc(a);\n        auto [rb, cb] = rc(b);\n        return abs(ra - rb) + abs(ca - cb);\n    }\n\n    // ============================================================\n    // Circular-order evaluation\n    // ============================================================\n    struct EvalRes {\n        ll cost;\n        int start;\n    };\n\n    EvalRes eval_circle(const vector<int>& seq) const {\n        int K = (int)seq.size();\n        if (K == 0) return {0, 0};\n\n        ll pref[405];\n        int ed[405];\n\n        pref[0] = 0;\n        for (int i = 0; i < K; ++i) pref[i + 1] = pref[i] + val[seq[i]];\n\n        ll mn = pref[0];\n        for (int s = 1; s < K; ++s) mn = min(mn, pref[s]);\n\n        ll total_edge = 0;\n        ll loaded_const = 0;\n        for (int i = 0; i < K; ++i) {\n            int j = (i + 1 == K ? 0 : i + 1);\n            ed[i] = dist(seq[i], seq[j]);\n            total_edge += ed[i];\n            loaded_const += (pref[i + 1] - mn) * 1LL * ed[i];\n        }\n\n        ll best = INF64;\n        int bestS = 0;\n        for (int s = 0; s < K; ++s) {\n            if (pref[s] != mn) continue;\n            int omitted = ed[(s - 1 + K) % K];\n            ll var = 100LL * (total_edge - omitted + dist0(seq[s])) + loaded_const;\n            if (var < best) {\n                best = var;\n                bestS = s;\n            }\n        }\n        return {best, bestS};\n    }\n\n    void update_best_circle(const vector<int>& seq, const EvalRes& ev) {\n        if (ev.cost < best_var) {\n            best_var = ev.cost;\n            best_kind = 0;\n            best_circle = seq;\n            best_start = ev.start;\n        }\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : seq) {\n            uint64_t z = (uint64_t)(x + 1) * 0x9e3779b97f4a7c15ULL;\n            h ^= z;\n            h *= 1099511628211ULL;\n        }\n        h ^= (uint64_t)seq.size() + 0x517cc1b727220a95ULL;\n        return h;\n    }\n\n    void consider_circle(const vector<int>& seq) {\n        EvalRes ev = eval_circle(seq);\n        update_best_circle(seq, ev);\n\n        uint64_t h = hash_seq(seq);\n        if (seed_hashes.insert(h).second) {\n            seed_pool.push_back({ev.cost, seq});\n        }\n    }\n\n    // ============================================================\n    // Geometric order generators\n    // ============================================================\n    pair<int,int> transform_point(pair<int,int> p, int flip, int rot) const {\n        int r = p.first, c = p.second;\n        if (flip) c = N - 1 - c;\n        for (int k = 0; k < rot; ++k) {\n            int nr = c;\n            int nc = N - 1 - r;\n            r = nr;\n            c = nc;\n        }\n        return {r, c};\n    }\n\n    vector<int> transform_and_compress(const vector<pair<int,int>>& base, int flip, int rot, bool rev) const {\n        vector<int> seq;\n        seq.reserve(nz_ids.size());\n        if (!rev) {\n            for (auto p : base) {\n                auto q = transform_point(p, flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        } else {\n            for (int i = (int)base.size() - 1; i >= 0; --i) {\n                auto q = transform_point(base[i], flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_row_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            if ((r & 1) == 0) {\n                for (int c = 0; c < N; ++c) seq.push_back({r, c});\n            } else {\n                for (int c = N - 1; c >= 0; --c) seq.push_back({r, c});\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_canonical_cycle_like() const {\n        vector<pair<int,int>> cyc;\n        cyc.reserve(M);\n        for (int c = 0; c < N; ++c) cyc.push_back({0, c});\n        for (int r = 1; r < N; ++r) {\n            if (r & 1) {\n                for (int c = N - 1; c >= 1; --c) cyc.push_back({r, c});\n            } else {\n                for (int c = 1; c < N; ++c) cyc.push_back({r, c});\n            }\n        }\n        for (int r = N - 1; r >= 1; --r) cyc.push_back({r, 0});\n        return cyc;\n    }\n\n    vector<pair<int,int>> make_diag_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            vector<pair<int,int>> tmp;\n            int r0 = max(0, s - (N - 1));\n            int r1 = min(N - 1, s);\n            for (int r = r0; r <= r1; ++r) {\n                int c = s - r;\n                tmp.push_back({r, c});\n            }\n            if (s & 1) reverse(tmp.begin(), tmp.end());\n            for (auto p : tmp) seq.push_back(p);\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_block_snake(int B) const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        vector<int> block_cols;\n        for (int bc = 0; bc < N; bc += B) block_cols.push_back(bc);\n\n        for (int br = 0; br < N; br += B) {\n            auto bcs = block_cols;\n            if (((br / B) & 1) == 1) reverse(bcs.begin(), bcs.end());\n\n            for (int bc : bcs) {\n                int rlim = min(N, br + B);\n                int clim = min(N, bc + B);\n                for (int r = br; r < rlim; ++r) {\n                    if (((r - br) & 1) == 0) {\n                        for (int c = bc; c < clim; ++c) seq.push_back({r, c});\n                    } else {\n                        for (int c = clim - 1; c >= bc; --c) seq.push_back({r, c});\n                    }\n                }\n            }\n        }\n        return seq;\n    }\n\n    static void hilbert_rot(int n, int &x, int &y, int rx, int ry) {\n        if (ry == 0) {\n            if (rx == 1) {\n                x = n - 1 - x;\n                y = n - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    static int hilbert_xy2d(int n, int x, int y) {\n        int rx, ry, s;\n        int d = 0;\n        for (s = n / 2; s > 0; s /= 2) {\n            rx = (x & s) ? 1 : 0;\n            ry = (y & s) ? 1 : 0;\n            d += s * s * ((3 * rx) ^ ry);\n            hilbert_rot(n, x, y, rx, ry);\n        }\n        return d;\n    }\n\n    static unsigned morton_xy2d(unsigned x, unsigned y) {\n        auto part1by1 = [](unsigned x) -> unsigned {\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        };\n        return (part1by1(y) << 1) | part1by1(x);\n    }\n\n    vector<pair<int,int>> make_hilbert_order() const {\n        vector<pair<int, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        int S = 32;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int d = hilbert_xy2d(S, c, r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_morton_order() const {\n        vector<pair<unsigned, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                unsigned d = morton_xy2d((unsigned)c, (unsigned)r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_spiral() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; ++c) seq.push_back({top, c});\n            ++top;\n            for (int r = top; r <= bottom; ++r) seq.push_back({r, right});\n            --right;\n            if (top <= bottom) {\n                for (int c = right; c >= left; --c) seq.push_back({bottom, c});\n                --bottom;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; --r) seq.push_back({r, left});\n                ++left;\n            }\n        }\n        return seq;\n    }\n\n    void try_geometric_orders() {\n        vector<vector<pair<int,int>>> bases;\n        bases.push_back(make_row_snake());\n        bases.push_back(make_canonical_cycle_like());\n        bases.push_back(make_diag_snake());\n        bases.push_back(make_block_snake(2));\n        bases.push_back(make_block_snake(4));\n        bases.push_back(make_block_snake(5));\n        bases.push_back(make_hilbert_order());\n        bases.push_back(make_morton_order());\n        bases.push_back(make_spiral());\n\n        for (const auto& base : bases) {\n            for (int flip = 0; flip < 2; ++flip) {\n                for (int rot = 0; rot < 4; ++rot) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        auto seq = transform_and_compress(base, flip, rot, rev);\n                        consider_circle(seq);\n                    }\n                }\n            }\n        }\n    }\n\n    void try_projection_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n        vector<pair<int,int>> coeffs = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}\n        };\n\n        for (auto [a, b] : coeffs) {\n            for (int sr : {-1, 1}) {\n                for (int sc : {-1, 1}) {\n                    vector<int> seq = nz_ids;\n                    sort(seq.begin(), seq.end(), [&](int x, int y) {\n                        auto [rx, cx] = rc(x);\n                        auto [ry, cy] = rc(y);\n                        int p1 = a * sr * rx + b * sc * cx;\n                        int p2 = a * sr * ry + b * sc * cy;\n                        if (p1 != p2) return p1 < p2;\n                        int q1 = b * sr * rx - a * sc * cx;\n                        int q2 = b * sr * ry - a * sc * cy;\n                        if (q1 != q2) return q1 < q2;\n                        return x < y;\n                    });\n                    consider_circle(seq);\n                    reverse(seq.begin(), seq.end());\n                    consider_circle(seq);\n                }\n            }\n        }\n    }\n\n    // ============================================================\n    // Greedy order builders\n    // ============================================================\n    vector<int> build_greedy_linear(int lambda, int start_id) const {\n        int K = (int)nz_ids.size();\n        vector<char> used(M, 0);\n        vector<int> seq;\n        seq.reserve(K);\n\n        ll load = 0;\n        int cur = -1; // origin if -1\n\n        if (start_id != -1) {\n            used[start_id] = 1;\n            seq.push_back(start_id);\n            load += val[start_id];\n            cur = start_id;\n        }\n\n        while ((int)seq.size() < K) {\n            bool has_feasible_neg = false;\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                if (val[v] < 0 && load >= -1LL * val[v]) {\n                    has_feasible_neg = true;\n                    break;\n                }\n            }\n\n            int best = -1;\n            ll best_score = INF64;\n            int best_d = 0;\n            int best_gain = 0;\n\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                int hv = val[v];\n\n                if (has_feasible_neg) {\n                    if (hv >= 0) continue;\n                    if (load < -1LL * hv) continue;\n                } else {\n                    if (hv <= 0) continue;\n                }\n\n                int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                int gain = abs(hv);\n\n                ll score;\n                if (hv < 0) score = 1LL * lambda * d - 2LL * gain;\n                else        score = 1LL * lambda * d - 1LL * gain;\n\n                if (best == -1 ||\n                    score < best_score ||\n                    (score == best_score && (d < best_d ||\n                    (d == best_d && gain > best_gain)))) {\n                    best = v;\n                    best_score = score;\n                    best_d = d;\n                    best_gain = gain;\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) {\n                    if (used[v]) continue;\n                    int hv = val[v];\n                    if (hv > 0) {\n                        int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                        int gain = abs(hv);\n                        ll score = 1LL * lambda * d - 1LL * gain;\n                        if (best == -1 ||\n                            score < best_score ||\n                            (score == best_score && (d < best_d ||\n                            (d == best_d && gain > best_gain)))) {\n                            best = v;\n                            best_score = score;\n                            best_d = d;\n                            best_gain = gain;\n                        }\n                    }\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) if (!used[v]) { best = v; break; }\n            }\n\n            used[best] = 1;\n            seq.push_back(best);\n            load += val[best];\n            cur = best;\n        }\n        return seq;\n    }\n\n    vector<int> select_greedy_starts() const {\n        vector<int> starts;\n        vector<char> seen(M, 0);\n\n        auto add = [&](int v) {\n            if (v == -1) {\n                starts.push_back(v);\n                return;\n            }\n            if (!seen[v]) {\n                seen[v] = 1;\n                starts.push_back(v);\n            }\n        };\n\n        add(-1);\n\n        if ((int)pos_ids.size() <= 40) {\n            for (int v : pos_ids) add(v);\n            return starts;\n        }\n\n        vector<int> tmp = pos_ids;\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (val[a] != val[b]) return val[a] > val[b];\n            return dist0(a) < dist0(b);\n        });\n        for (int i = 0; i < min(24, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (dist0(a) != dist0(b)) return dist0(a) < dist0(b);\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(24, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            int sa = 5 * val[a] - 3 * dist0(a);\n            int sb = 5 * val[b] - 3 * dist0(b);\n            if (sa != sb) return sa > sb;\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(24, (int)tmp.size()); ++i) add(tmp[i]);\n\n        return starts;\n    }\n\n    void try_greedy_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        vector<int> lambdas = {2, 4, 8, 16, 32};\n        vector<int> starts = select_greedy_starts();\n\n        for (int lambda : lambdas) {\n            for (int st : starts) {\n                auto seq = build_greedy_linear(lambda, st);\n                consider_circle(seq);\n                reverse(seq.begin(), seq.end());\n                consider_circle(seq);\n            }\n        }\n    }\n\n    // ============================================================\n    // Local search on circular orders\n    // ============================================================\n    void polish_adjacent(vector<int>& seq, ll& cur_cost,\n                         const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 1) return;\n\n        for (int pass = 0; pass < 2; ++pass) {\n            bool improved = false;\n            for (int i = 0; i + 1 < K; ++i) {\n                if ((i & 31) == 0 && chrono::steady_clock::now() >= end_time) return;\n\n                swap(seq[i], seq[i + 1]);\n                EvalRes ev = eval_circle(seq);\n                if (ev.cost < cur_cost) {\n                    cur_cost = ev.cost;\n                    improved = true;\n                    update_best_circle(seq, ev);\n                } else {\n                    swap(seq[i], seq[i + 1]);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void improve_seed(vector<int> seq,\n                      const chrono::steady_clock::time_point& end_time,\n                      mt19937& rng) {\n        int K = (int)seq.size();\n        if (K <= 1) {\n            EvalRes ev = eval_circle(seq);\n            update_best_circle(seq, ev);\n            return;\n        }\n\n        EvalRes cur_ev = eval_circle(seq);\n        ll cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        polish_adjacent(seq, cur_cost, end_time);\n        cur_ev = eval_circle(seq);\n        cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        vector<int> best_local_seq = seq;\n        ll best_local_cost = cur_cost;\n\n        auto start_time = chrono::steady_clock::now();\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        double T0 = 3000.0;\n        double T1 = 3.0;\n        double temp = T0;\n\n        uint64_t iter = 0;\n        while (true) {\n            if ((iter & 255ULL) == 0) {\n                auto now = chrono::steady_clock::now();\n                if (now >= end_time) break;\n                double elapsed = chrono::duration<double>(now - start_time).count();\n                double total = chrono::duration<double>(end_time - start_time).count();\n                double progress = (total <= 0 ? 1.0 : min(1.0, elapsed / total));\n                temp = T0 * pow(T1 / T0, progress);\n            }\n            ++iter;\n\n            vector<int> tmp = seq;\n            int type = (int)(rng() % 3);\n\n            if (type == 0) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                swap(tmp[i], tmp[j]);\n            } else if (type == 1) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                int x = tmp[i];\n                if (i < j) {\n                    for (int p = i; p < j; ++p) tmp[p] = tmp[p + 1];\n                    tmp[j] = x;\n                } else {\n                    for (int p = i; p > j; --p) tmp[p] = tmp[p - 1];\n                    tmp[j] = x;\n                }\n            } else {\n                int l = (int)(rng() % K);\n                int r = (int)(rng() % K);\n                if (l > r) swap(l, r);\n                if (l == r) continue;\n                reverse(tmp.begin() + l, tmp.begin() + r + 1);\n            }\n\n            EvalRes nev = eval_circle(tmp);\n            ll nv = nev.cost;\n            ll delta = nv - cur_cost;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-(double)delta / temp);\n                if (urd(rng) < prob) accept = true;\n            }\n\n            if (accept) {\n                seq.swap(tmp);\n                cur_cost = nv;\n                cur_ev = nev;\n                if (cur_cost < best_local_cost) {\n                    best_local_cost = cur_cost;\n                    best_local_seq = seq;\n                    update_best_circle(best_local_seq, cur_ev);\n                }\n            }\n        }\n\n        if (!best_local_seq.empty()) {\n            EvalRes ev = eval_circle(best_local_seq);\n            ll c = ev.cost;\n            polish_adjacent(best_local_seq, c, end_time);\n            ev = eval_circle(best_local_seq);\n            update_best_circle(best_local_seq, ev);\n        }\n    }\n\n    void improve_orders_by_local_search() {\n        if (seed_pool.empty()) return;\n\n        sort(seed_pool.begin(), seed_pool.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int S = min(6, (int)seed_pool.size());\n        mt19937 rng(123456789);\n\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(1700);\n        for (int i = 0; i < S; ++i) {\n            auto now = chrono::steady_clock::now();\n            if (now >= deadline) break;\n            auto remain = deadline - now;\n            auto local_end = now + remain / (S - i);\n            improve_seed(seed_pool[i].second, local_end, rng);\n        }\n    }\n\n    // ============================================================\n    // Cross-tree family\n    // ============================================================\n    TreePlan build_tree_plan(int rr, int cc, int orient) const {\n        TreePlan tp;\n        tp.root = id(rr, cc);\n        tp.orient = orient;\n        tp.children.assign(M, {});\n        tp.parent.assign(M, -1);\n        tp.sum.assign(M, 0);\n        tp.sz.assign(M, 1);\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                if (v == tp.root) continue;\n\n                int pr = r, pc = c;\n                if (orient == 0) {\n                    if (c != cc) pc += (c < cc ? 1 : -1);\n                    else pr += (r < rr ? 1 : -1);\n                } else {\n                    if (r != rr) pr += (r < rr ? 1 : -1);\n                    else pc += (c < cc ? 1 : -1);\n                }\n\n                int p = id(pr, pc);\n                tp.parent[v] = p;\n                tp.children[p].push_back(v);\n            }\n        }\n\n        function<void(int)> dfs = [&](int v) {\n            tp.sum[v] = val[v];\n            tp.sz[v] = 1;\n            for (int u : tp.children[v]) {\n                dfs(u);\n                tp.sum[v] += tp.sum[u];\n                tp.sz[v] += tp.sz[u];\n            }\n        };\n        dfs(tp.root);\n        return tp;\n    }\n\n    int choose_task(int v, const TreePlan &tp, const vector<int>& tasks,\n                    const vector<char>& used, ll cur_load) const {\n        auto get_delta = [&](int tk) -> ll {\n            if (tk == -1) return val[v];\n            return tp.sum[tk];\n        };\n        auto get_sz = [&](int tk) -> int {\n            if (tk == -1) return 0;\n            return tp.sz[tk];\n        };\n\n        int best_neg = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d >= 0) continue;\n            if (cur_load < -d) continue;\n\n            if (best_neg == -2) {\n                best_neg = i;\n            } else {\n                ll d1 = -get_delta(tasks[i]);\n                ll d2 = -get_delta(tasks[best_neg]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_neg]);\n\n                bool better = false;\n                if (s1 == 0 && s2 == 0) better = d1 > d2;\n                else if (s1 == 0) better = true;\n                else if (s2 == 0) better = false;\n                else {\n                    __int128 lhs = (__int128)d1 * s2;\n                    __int128 rhs = (__int128)d2 * s1;\n                    if (lhs != rhs) better = lhs > rhs;\n                    else better = d1 > d2;\n                }\n                if (better) best_neg = i;\n            }\n        }\n        if (best_neg != -2) return best_neg;\n\n        int best_pos = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d < 0) continue;\n\n            if (best_pos == -2) {\n                best_pos = i;\n            } else {\n                ll p1 = get_delta(tasks[i]);\n                ll p2 = get_delta(tasks[best_pos]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_pos]);\n\n                bool better = false;\n                if (p1 == 0 && p2 > 0) better = true;\n                else if (p1 > 0 && p2 == 0) better = false;\n                else if (p1 == 0 && p2 == 0) better = false;\n                else {\n                    if (s1 == 0 && s2 == 0) better = p1 < p2;\n                    else if (s1 == 0) better = false;\n                    else if (s2 == 0) better = true;\n                    else {\n                        __int128 lhs = (__int128)p1 * s2;\n                        __int128 rhs = (__int128)p2 * s1;\n                        if (lhs != rhs) better = lhs < rhs;\n                        else better = p1 < p2;\n                    }\n                }\n                if (better) best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    struct EvalState {\n        ll load = 0;\n        ll loaded_move = 0;\n        bool ok = true;\n    };\n\n    void eval_tree_dfs(int v, const TreePlan &tp, EvalState &st) const {\n        if (!st.ok) return;\n\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, st.load);\n            if (idx < 0) {\n                st.ok = false;\n                return;\n            }\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                int hv = val[v];\n                if (hv < 0 && st.load < -1LL * hv) {\n                    st.ok = false;\n                    return;\n                }\n                st.load += hv;\n                if (st.load < 0) {\n                    st.ok = false;\n                    return;\n                }\n            } else {\n                if (tp.sum[tk] < 0 && st.load < -1LL * tp.sum[tk]) {\n                    st.ok = false;\n                    return;\n                }\n                st.loaded_move += st.load;\n                eval_tree_dfs(tk, tp, st);\n                if (!st.ok) return;\n                st.loaded_move += st.load;\n            }\n        }\n    }\n\n    ll eval_tree_plan(TreePlan &tp) const {\n        EvalState st;\n        eval_tree_dfs(tp.root, tp, st);\n        if (!st.ok || st.load != 0) return INF64;\n\n        auto [rr, cc] = rc(tp.root);\n        ll reposition = rr + cc;\n        ll moves = reposition + 2LL * (M - 1);\n        tp.var_cost = 100LL * moves + st.loaded_move;\n        return tp.var_cost;\n    }\n\n    void try_tree_family() {\n        for (int rr = 0; rr < N; ++rr) {\n            for (int cc = 0; cc < N; ++cc) {\n                for (int orient = 0; orient < 2; ++orient) {\n                    TreePlan tp = build_tree_plan(rr, cc, orient);\n                    ll var = eval_tree_plan(tp);\n                    if (var < best_var) {\n                        best_var = var;\n                        best_kind = 1;\n                        best_tree = move(tp);\n                    }\n                }\n            }\n        }\n    }\n\n    // ============================================================\n    // Output helpers\n    // ============================================================\n    void push_move_char(char ch) {\n        ans.emplace_back(1, ch);\n    }\n\n    void move_to(int tr, int tc) {\n        while (cur_r < tr) { push_move_char('D'); ++cur_r; }\n        while (cur_r > tr) { push_move_char('U'); --cur_r; }\n        while (cur_c < tc) { push_move_char('R'); ++cur_c; }\n        while (cur_c > tc) { push_move_char('L'); --cur_c; }\n    }\n\n    void move_to_id(int v) {\n        auto [r, c] = rc(v);\n        move_to(r, c);\n    }\n\n    void move_edge(int a, int b) {\n        auto [r1, c1] = rc(a);\n        auto [r2, c2] = rc(b);\n        if (r2 == r1 + 1 && c2 == c1) push_move_char('D');\n        else if (r2 == r1 - 1 && c2 == c1) push_move_char('U');\n        else if (r2 == r1 && c2 == c1 + 1) push_move_char('R');\n        else if (r2 == r1 && c2 == c1 - 1) push_move_char('L');\n        else assert(false);\n        cur_r = r2;\n        cur_c = c2;\n    }\n\n    void output_order_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        int K = (int)best_circle.size();\n        if (K == 0) return;\n\n        vector<int> ord;\n        ord.reserve(K);\n        for (int t = 0; t < K; ++t) ord.push_back(best_circle[(best_start + t) % K]);\n\n        move_to_id(ord[0]);\n\n        for (int i = 0; i < K; ++i) {\n            int v = ord[i];\n            auto [r, c] = rc(v);\n            assert(cur_r == r && cur_c == c);\n\n            if (val[v] > 0) {\n                ans.push_back(\"+\" + to_string(val[v]));\n                truck += val[v];\n            } else {\n                assert(truck >= -1LL * val[v]);\n                ans.push_back(\"-\" + to_string(-val[v]));\n                truck += val[v];\n            }\n\n            if (i + 1 < K) move_to_id(ord[i + 1]);\n        }\n        assert(truck == 0);\n    }\n\n    void output_tree_dfs(int v, const TreePlan &tp) {\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, truck);\n            assert(idx >= 0);\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                if (val[v] > 0) {\n                    ans.push_back(\"+\" + to_string(val[v]));\n                    truck += val[v];\n                } else if (val[v] < 0) {\n                    assert(truck >= -1LL * val[v]);\n                    ans.push_back(\"-\" + to_string(-val[v]));\n                    truck += val[v];\n                }\n            } else {\n                move_edge(v, tk);\n                output_tree_dfs(tk, tp);\n                move_edge(tk, v);\n            }\n        }\n    }\n\n    void output_tree_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        auto [rr, cc] = rc(best_tree.root);\n        move_to(rr, cc);\n        output_tree_dfs(best_tree.root, best_tree);\n        assert(truck == 0);\n    }\n\n    // ============================================================\n    // Solve\n    // ============================================================\n    void solve() {\n        try_geometric_orders();\n        try_projection_orders();\n        try_greedy_orders();\n\n        // keep tree family as an alternative\n        try_tree_family();\n\n        // local search only for order-type seeds\n        improve_orders_by_local_search();\n\n        if (best_kind == 1) output_tree_solution();\n        else output_order_solution();\n\n        assert((int)ans.size() <= 100000);\n        for (auto &s : ans) cout << s << '\\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>> h(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n    }\n\n    Solver solver(N, h);\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Solver {\n    int N, M, T, S;\n    vector<vector<int>> X;\n    vector<int> V;\n\n    vector<vector<int>> neighPos;\n    vector<pair<int,int>> edgesPos;\n    vector<int> posOrder;\n    vector<int> centers;\n\n    XorShift64 rng;\n\n    void build_grid() {\n        int P = N * N;\n        neighPos.assign(P, {});\n        edgesPos.clear();\n\n        auto id = [&](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 p = id(r, c);\n                if (r + 1 < N) {\n                    int q = id(r + 1, c);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n                if (c + 1 < N) {\n                    int q = id(r, c + 1);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n            }\n        }\n\n        vector<int> ps(P);\n        iota(ps.begin(), ps.end(), 0);\n\n        auto degree = [&](int p) { return (int)neighPos[p].size(); };\n        auto dist2_center = [&](int p) {\n            int r = p / N, c = p % N;\n            double cr = (N - 1) / 2.0;\n            double cc = (N - 1) / 2.0;\n            double dr = r - cr;\n            double dc = c - cc;\n            return dr * dr + dc * dc;\n        };\n\n        sort(ps.begin(), ps.end(), [&](int a, int b) {\n            int da = degree(a), db = degree(b);\n            if (da != db) return da > db;\n            double xa = dist2_center(a), xb = dist2_center(b);\n            if (xa != xb) return xa < xb;\n            return a < b;\n        });\n        posOrder = ps;\n\n        // Central 2x2 cells for N=6, but written generally.\n        int r0 = N / 2 - 1, r1 = N / 2;\n        int c0 = N / 2 - 1, c1 = N / 2;\n        centers = {id(r0, c0), id(r0, c1), id(r1, c0), id(r1, c1)};\n    }\n\n    bool read_seed_set() {\n        X.assign(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> X[i][j])) return false;\n            }\n        }\n        return true;\n    }\n\n    struct TurnInfo {\n        vector<double> rarityW;\n        vector<double> uniqBonus;\n        vector<double> weightedScore;\n        vector<double> partnerScore; // relative to eliteMain\n        int eliteMain;\n        int eliteBestV;\n    };\n\n    TurnInfo analyze_turn(int turn) {\n        TurnInfo info;\n        info.rarityW.assign(M, 1.0);\n        info.uniqBonus.assign(S, 0.0);\n        info.weightedScore.assign(S, 0.0);\n        info.partnerScore.assign(S, 0.0);\n\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> best1(M, -1), best2(M, -1), id1(M, -1);\n\n        for (int l = 0; l < M; l++) {\n            int b1 = -1, b2 = -1, who = -1;\n            for (int i = 0; i < S; i++) {\n                int v = X[i][l];\n                if (v > b1) {\n                    b2 = b1;\n                    b1 = v;\n                    who = i;\n                } else if (v > b2) {\n                    b2 = v;\n                }\n            }\n            best1[l] = b1;\n            best2[l] = max(0, b2);\n            id1[l] = who;\n\n            int gap = best1[l] - best2[l];\n            info.uniqBonus[who] += gap;\n\n            // Rare max coordinates should matter more, but keep weights bounded.\n            info.rarityW[l] = 1.0 + min(2.5, 0.06 * gap);\n        }\n\n        for (int i = 0; i < S; i++) {\n            double ws = 0.0;\n            for (int l = 0; l < M; l++) ws += info.rarityW[l] * X[i][l];\n            info.weightedScore[i] = ws;\n        }\n\n        // Main elite: blend total value + rarity preservation + weighted quality.\n        info.eliteBestV = max_element(V.begin(), V.end()) - V.begin();\n\n        double bestEliteScore = -1e100;\n        info.eliteMain = 0;\n        double uniqCoef = 0.7 + 0.9 * explore;\n        double wcoef = 0.10 + 0.10 * explore;\n        for (int i = 0; i < S; i++) {\n            double sc = V[i] + uniqCoef * info.uniqBonus[i] + wcoef * (info.weightedScore[i] - V[i]);\n            if (sc > bestEliteScore) {\n                bestEliteScore = sc;\n                info.eliteMain = i;\n            }\n        }\n\n        int e = info.eliteMain;\n        double riskCoef = 0.25 + 0.55 * (1.0 - explore);\n\n        for (int i = 0; i < S; i++) {\n            if (i == e) {\n                info.partnerScore[i] = -1e100;\n                continue;\n            }\n            double improve = 0.0, risk = 0.0;\n            for (int l = 0; l < M; l++) {\n                int a = X[i][l];\n                int b = X[e][l];\n                if (a > b) improve += info.rarityW[l] * (a - b);\n                else if (a < b) risk += info.rarityW[l] * (b - a);\n            }\n            info.partnerScore[i] = improve - riskCoef * risk + 0.12 * V[i];\n        }\n\n        return info;\n    }\n\n    vector<int> choose_seeds(int turn, const TurnInfo& info) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        int P = N * N;\n\n        vector<char> used(S, 0);\n        vector<int> selected;\n\n        auto add_force = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Force main elite.\n        add_force(info.eliteMain);\n\n        // Force current best-by-total as well.\n        add_force(info.eliteBestV);\n\n        // Early: keep best seed of each criterion to avoid losing rare max values.\n        if (explore > 0.70) {\n            for (int l = 0; l < M; l++) {\n                int bestId = 0;\n                for (int i = 1; i < S; i++) {\n                    if (X[i][l] > X[bestId][l] ||\n                        (X[i][l] == X[bestId][l] && V[i] > V[bestId])) {\n                        bestId = i;\n                    }\n                }\n                add_force(bestId);\n            }\n        }\n\n        vector<double> candBonus(S, 0.0);\n\n        // Rankings.\n        vector<int> ordV(S), ordW(S), ordP(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        iota(ordW.begin(), ordW.end(), 0);\n        iota(ordP.begin(), ordP.end(), 0);\n\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n        sort(ordW.begin(), ordW.end(), [&](int a, int b) {\n            if (info.weightedScore[a] != info.weightedScore[b]) return info.weightedScore[a] > info.weightedScore[b];\n            return a < b;\n        });\n        sort(ordP.begin(), ordP.end(), [&](int a, int b) {\n            if (info.partnerScore[a] != info.partnerScore[b]) return info.partnerScore[a] > info.partnerScore[b];\n            return a < b;\n        });\n\n        int kTotal = 8 + (int)llround(6 * (1.0 - explore));\n        int kWeighted = 6 + (int)llround(4 * explore);\n        int kPartner = 6 + (int)llround(6 * (1.0 - explore));\n        int kCrit = (explore > 0.55 ? 2 : (explore > 0.20 ? 1 : 0));\n\n        for (int r = 0; r < min(kTotal, S); r++) candBonus[ordV[r]] += 40.0 - 2.0 * r;\n        for (int r = 0; r < min(kWeighted, S); r++) candBonus[ordW[r]] += 24.0 - 2.0 * r;\n        for (int r = 0; r < min(kPartner, S); r++) candBonus[ordP[r]] += 28.0 - 2.0 * r;\n\n        if (info.eliteMain >= 0) candBonus[info.eliteMain] += 40.0;\n        if (info.eliteBestV >= 0) candBonus[info.eliteBestV] += 20.0;\n\n        if (kCrit > 0) {\n            for (int l = 0; l < M; l++) {\n                vector<int> ids(S);\n                iota(ids.begin(), ids.end(), 0);\n                partial_sort(ids.begin(), ids.begin() + min(kCrit, S), ids.end(), [&](int a, int b) {\n                    if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                    return V[a] > V[b];\n                });\n                for (int r = 0; r < kCrit; r++) {\n                    candBonus[ids[r]] += (r == 0 ? 16.0 : 8.0) * info.rarityW[l];\n                }\n            }\n        }\n\n        vector<int> bestSel(M, 0);\n        for (int id : selected) {\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[id][l]);\n        }\n\n        double coverW = 0.65 * explore + 0.20;\n        double partnerW = 0.25 + 0.90 * (1.0 - explore);\n        double weightedExtraW = 0.10 + 0.20 * explore;\n        double uniqW = 0.15 + 0.15 * explore;\n\n        while ((int)selected.size() < P) {\n            double bestScore = -1e100;\n            int bestId = -1;\n\n            for (int i = 0; i < S; i++) if (!used[i]) {\n                double cov = 0.0;\n                for (int l = 0; l < M; l++) {\n                    if (X[i][l] > bestSel[l]) cov += info.rarityW[l] * (X[i][l] - bestSel[l]);\n                }\n\n                double sc =\n                    candBonus[i]\n                    + 1.00 * V[i]\n                    + coverW * cov\n                    + partnerW * max(0.0, info.partnerScore[i])\n                    + weightedExtraW * (info.weightedScore[i] - V[i])\n                    + uniqW * info.uniqBonus[i];\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            used[bestId] = 1;\n            selected.push_back(bestId);\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[bestId][l]);\n        }\n\n        return selected;\n    }\n\n    struct LayoutResult {\n        double score = -1e100;\n        vector<int> layoutGlobal;\n    };\n\n    double compute_pair_base(int ga, int gb, int turn) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        double mu = 0.5 * (V[ga] + V[gb]);\n\n        double sq = 0.0;\n        int diffCnt = 0;\n        int ub = 0;\n        for (int l = 0; l < M; l++) {\n            int d = X[ga][l] - X[gb][l];\n            sq += 1.0 * d * d;\n            if (d != 0) diffCnt++;\n            ub += max(X[ga][l], X[gb][l]);\n        }\n        double sigma = 0.5 * sqrt(sq);\n\n        // Immediate one-child quality approximation.\n        double q = mu + (0.55 + 0.20 * (1.0 - explore)) * sigma;\n\n        // Early turns: upper-bound potential matters more.\n        double gamma = 0.45 * explore;\n        double riskPenalty = (0.45 + 0.35 * (1.0 - explore)) * diffCnt;\n\n        return (1.0 - gamma) * q + gamma * (ub - riskPenalty);\n    }\n\n    double arrangement_score(\n        const vector<int>& perm,                  // position -> local seed\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,    // position adjacency multiplier\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        double sc = 0.0;\n        int P = N * N;\n        for (int p = 0; p < P; p++) {\n            sc += posCoef[p] * nodeVal[perm[p]];\n        }\n        for (auto [u, v] : edgesPos) {\n            sc += multMat[u][v] * pairBase[perm[u]][perm[v]];\n        }\n        return sc;\n    }\n\n    double delta_swap(\n        vector<int>& perm, int p, int q,\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        if (p == q) return 0.0;\n\n        array<pair<int,int>, 8> aff{};\n        int cnt = 0;\n\n        auto add_edge = [&](int a, int b) {\n            if (a > b) swap(a, b);\n            for (int i = 0; i < cnt; i++) {\n                if (aff[i].first == a && aff[i].second == b) return;\n            }\n            aff[cnt++] = {a, b};\n        };\n\n        for (int nb : neighPos[p]) add_edge(p, nb);\n        for (int nb : neighPos[q]) add_edge(q, nb);\n\n        double oldv = 0.0, newv = 0.0;\n\n        oldv += posCoef[p] * nodeVal[perm[p]] + posCoef[q] * nodeVal[perm[q]];\n        newv += posCoef[p] * nodeVal[perm[q]] + posCoef[q] * nodeVal[perm[p]];\n\n        auto get_seed_after = [&](int pos) -> int {\n            if (pos == p) return perm[q];\n            if (pos == q) return perm[p];\n            return perm[pos];\n        };\n\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            oldv += multMat[a][b] * pairBase[perm[a]][perm[b]];\n            newv += multMat[a][b] * pairBase[get_seed_after(a)][get_seed_after(b)];\n        }\n\n        return newv - oldv;\n    }\n\n    LayoutResult optimize_layout(const vector<int>& selected, const TurnInfo& info, int turn) {\n        int P = N * N;\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> localToGlobal = selected;\n        vector<int> globalToLocal(S, -1);\n        for (int i = 0; i < P; i++) globalToLocal[localToGlobal[i]] = i;\n\n        vector<vector<double>> pairBase(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                double w = compute_pair_base(localToGlobal[i], localToGlobal[j], turn);\n                pairBase[i][j] = pairBase[j][i] = w;\n            }\n        }\n\n        vector<double> nodeVal(P, 0.0);\n        for (int i = 0; i < P; i++) {\n            int g = localToGlobal[i];\n            nodeVal[i] =\n                0.12 * V[g]\n                + 0.18 * max(0.0, info.partnerScore[g])\n                + 0.08 * info.uniqBonus[g]\n                + 0.04 * (info.weightedScore[g] - V[g]);\n        }\n\n        vector<int> posCoef(P, 0);\n        for (int p = 0; p < P; p++) {\n            posCoef[p] = (int)neighPos[p].size() - 2; // corner 0, border 1, interior 2\n        }\n\n        vector<int> eliteCandidates;\n        if (globalToLocal[info.eliteMain] != -1) eliteCandidates.push_back(info.eliteMain);\n        if (info.eliteBestV != info.eliteMain && globalToLocal[info.eliteBestV] != -1) {\n            eliteCandidates.push_back(info.eliteBestV);\n        }\n        if (eliteCandidates.empty()) eliteCandidates.push_back(localToGlobal[0]);\n\n        LayoutResult best;\n\n        for (int eliteGlobal : eliteCandidates) {\n            int eliteLocal = globalToLocal[eliteGlobal];\n            if (eliteLocal < 0) continue;\n\n            for (int hubPos : centers) {\n                double hubBoost = 0.55 + 0.55 * (1.0 - explore);\n\n                vector<vector<double>> multMat(P, vector<double>(P, 0.0));\n                for (auto [u, v] : edgesPos) {\n                    double mul = 1.0 + ((u == hubPos || v == hubPos) ? hubBoost : 0.0);\n                    multMat[u][v] = multMat[v][u] = mul;\n                }\n\n                vector<int> perm(P, -1);\n                vector<char> usedLocal(P, 0);\n\n                perm[hubPos] = eliteLocal;\n                usedLocal[eliteLocal] = 1;\n\n                // Put good elite partners around the hub first.\n                vector<int> around = neighPos[hubPos];\n                vector<int> remSeeds;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) remSeeds.push_back(i);\n\n                sort(remSeeds.begin(), remSeeds.end(), [&](int a, int b) {\n                    int ga = localToGlobal[a], gb = localToGlobal[b];\n                    double sa =\n                        0.75 * max(0.0, info.partnerScore[ga]) +\n                        0.40 * V[ga] +\n                        0.10 * info.weightedScore[ga];\n                    double sb =\n                        0.75 * max(0.0, info.partnerScore[gb]) +\n                        0.40 * V[gb] +\n                        0.10 * info.weightedScore[gb];\n                    if (sa != sb) return sa > sb;\n                    return ga < gb;\n                });\n\n                int ptr = 0;\n                for (int p : around) {\n                    while (ptr < (int)remSeeds.size() && usedLocal[remSeeds[ptr]]) ptr++;\n                    if (ptr < (int)remSeeds.size()) {\n                        perm[p] = remSeeds[ptr];\n                        usedLocal[remSeeds[ptr]] = 1;\n                        ptr++;\n                    }\n                }\n\n                // Fill remaining positions by general node score.\n                vector<int> posFill;\n                for (int p : posOrder) {\n                    if (perm[p] == -1) posFill.push_back(p);\n                }\n\n                vector<int> seedFill;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) seedFill.push_back(i);\n\n                sort(seedFill.begin(), seedFill.end(), [&](int a, int b) {\n                    if (nodeVal[a] != nodeVal[b]) return nodeVal[a] > nodeVal[b];\n                    return localToGlobal[a] < localToGlobal[b];\n                });\n\n                for (int k = 0; k < (int)posFill.size(); k++) {\n                    perm[posFill[k]] = seedFill[k];\n                }\n\n                double cur = arrangement_score(perm, pairBase, multMat, nodeVal, posCoef);\n\n                // SA / hill-climb with elite fixed at hub.\n                vector<char> fixed(P, 0);\n                fixed[hubPos] = 1;\n\n                int ITER = 9000;\n                double T0 = 18.0;\n                double T1 = 0.15;\n\n                for (int it = 0; it < ITER; it++) {\n                    int p = rng.next_int(P);\n                    int q = rng.next_int(P);\n                    if (p == q || fixed[p] || fixed[q]) continue;\n\n                    double temp = T0 * pow(T1 / T0, (double)it / ITER);\n                    double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n\n                    if (d >= 0.0 || rng.next_double() < exp(d / temp)) {\n                        swap(perm[p], perm[q]);\n                        cur += d;\n                    }\n                }\n\n                // Final hill-climb.\n                for (int rep = 0; rep < 12; rep++) {\n                    double bestDelta = 1e-12;\n                    int bp = -1, bq = -1;\n                    for (int p = 0; p < P; p++) if (!fixed[p]) {\n                        for (int q = p + 1; q < P; q++) if (!fixed[q]) {\n                            double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n                            if (d > bestDelta) {\n                                bestDelta = d;\n                                bp = p;\n                                bq = q;\n                            }\n                        }\n                    }\n                    if (bp == -1) break;\n                    swap(perm[bp], perm[bq]);\n                    cur += bestDelta;\n                }\n\n                if (cur > best.score) {\n                    best.score = cur;\n                    best.layoutGlobal.assign(P, -1);\n                    for (int p = 0; p < P; p++) {\n                        best.layoutGlobal[p] = localToGlobal[perm[p]];\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> T;\n        S = 2 * N * (N - 1);\n\n        build_grid();\n        if (!read_seed_set()) return;\n\n        for (int turn = 0; turn < T; turn++) {\n            V.assign(S, 0);\n            for (int i = 0; i < S; i++) {\n                for (int l = 0; l < M; l++) V[i] += X[i][l];\n            }\n\n            TurnInfo info = analyze_turn(turn);\n            vector<int> selected = choose_seeds(turn, info);\n            LayoutResult res = optimize_layout(selected, info, turn);\n            vector<int> layout = res.layoutGlobal;\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    if (c) cout << ' ';\n                    cout << layout[r * N + c];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (!read_seed_set()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\nstatic inline bool operator==(const Pt& a, const Pt& b) { return a.x == b.x && a.y == b.y; }\n\nstatic const int DX[4] = {0, 1, 0, -1}; // R,D,L,U\nstatic const int DY[4] = {1, 0, -1, 0};\n\nstruct Goal {\n    bool ok = false;\n    int leaf = -1;\n    int dir = -1;\n    Pt rootPos{-1, -1};\n    Pt cell{-1, -1};\n    int cost = INT_MAX;\n    int md = INT_MAX;\n    int rd = INT_MAX;\n};\n\nstruct Problem {\n    int N, M, Vmax;\n    vector<string> s, t;\n\n    vector<Pt> surplusCells, deficitCells;\n    vector<vector<int>> sid, did;\n\n    Pt centroidAll() const {\n        long long sx = 0, sy = 0;\n        int c = 0;\n        for (auto &p : surplusCells) sx += p.x, sy += p.y, c++;\n        for (auto &p : deficitCells) sx += p.x, sy += p.y, c++;\n        Pt r;\n        if (c == 0) r = {N / 2, N / 2};\n        else {\n            r.x = (int)llround((double)sx / c);\n            r.y = (int)llround((double)sy / c);\n        }\n        r.x = max(0, min(N - 1, r.x));\n        r.y = max(0, min(N - 1, r.y));\n        return r;\n    }\n\n    Pt medianAll() const {\n        vector<int> xs, ys;\n        xs.reserve(surplusCells.size() + deficitCells.size());\n        ys.reserve(surplusCells.size() + deficitCells.size());\n        for (auto &p : surplusCells) xs.push_back(p.x), ys.push_back(p.y);\n        for (auto &p : deficitCells) xs.push_back(p.x), ys.push_back(p.y);\n        if (xs.empty()) return {N / 2, N / 2};\n        nth_element(xs.begin(), xs.begin() + xs.size() / 2, xs.end());\n        nth_element(ys.begin(), ys.begin() + ys.size() / 2, ys.end());\n        Pt r{xs[xs.size() / 2], ys[ys.size() / 2]};\n        r.x = max(0, min(N - 1, r.x));\n        r.y = max(0, min(N - 1, r.y));\n        return r;\n    }\n\n    Pt center() const {\n        return {N / 2, N / 2};\n    }\n};\n\nstruct SimResult {\n    bool complete = false;\n    int turns = (int)1e9;\n    Pt initialRoot{0, 0};\n    vector<int> len;\n    vector<string> ops;\n};\n\nstruct Simulator {\n    const Problem& P;\n\n    int N, K, Vp;\n    vector<int> len;\n\n    Pt initialRoot, root;\n    vector<int> dirLeaf;      // 0..3\n    vector<char> holding;     // per leaf id 1..K\n    int holdCnt = 0;\n\n    vector<char> aliveS, aliveD;\n    int remS = 0, remD = 0;\n\n    vector<string> ops;\n    int cutoffTurns;\n\n    Simulator(const Problem& prob, const vector<int>& lengths, Pt rootInit, int cutoff)\n        : P(prob), N(prob.N), K((int)lengths.size() - 1), Vp((int)lengths.size()),\n          len(lengths), initialRoot(rootInit), root(rootInit), cutoffTurns(cutoff)\n    {\n        dirLeaf.assign(Vp, 0);\n        holding.assign(Vp, false);\n        aliveS.assign(P.surplusCells.size(), true);\n        aliveD.assign(P.deficitCells.size(), true);\n        remS = (int)P.surplusCells.size();\n        remD = (int)P.deficitCells.size();\n    }\n\n    inline bool inb(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    inline int rotDist(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        return min(d, 4 - d);\n    }\n\n    inline int applyRot(int cur, char c) const {\n        if (c == 'L') return (cur + 3) & 3;\n        if (c == 'R') return (cur + 1) & 3;\n        return cur;\n    }\n\n    inline char oneStepRotToward(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'L';\n    }\n\n    inline Pt moveRoot(Pt p, char mv) const {\n        if (mv == 'U') p.x--;\n        else if (mv == 'D') p.x++;\n        else if (mv == 'L') p.y--;\n        else if (mv == 'R') p.y++;\n        return p;\n    }\n\n    inline bool isSurplusCell(int x, int y) const {\n        int id = P.sid[x][y];\n        return (id != -1 && aliveS[id]);\n    }\n\n    inline bool isDeficitCell(int x, int y) const {\n        int id = P.did[x][y];\n        return (id != -1 && aliveD[id]);\n    }\n\n    Goal findGoal(bool wantDrop) const {\n        Goal best;\n        if (wantDrop) {\n            if (holdCnt == 0 || remD == 0) return best;\n            for (int id = 0; id < (int)P.deficitCells.size(); id++) {\n                if (!aliveD[id]) continue;\n                const Pt& c = P.deficitCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (!holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        } else {\n            if (holdCnt == K || remS == 0) return best;\n            for (int id = 0; id < (int)P.surplusCells.size(); id++) {\n                if (!aliveS[id]) continue;\n                const Pt& c = P.surplusCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        }\n        return best;\n    }\n\n    bool chooseMode(const Goal& gp, const Goal& gd) const {\n        // true => drop mode, false => pick mode\n        if (remD == 0 && holdCnt > 0) return true;\n        if (holdCnt == 0) return false;\n        if (holdCnt == K) return true;\n        if (!gd.ok) return false;\n        if (!gp.ok) return true;\n\n        if (holdCnt * 2 < K) {\n            if (gd.cost + 2 < gp.cost) return true;\n            return false;\n        } else {\n            if (gp.cost + 2 < gd.cost) return false;\n            return true;\n        }\n    }\n\n    struct Edge {\n        int cellIdx;\n        char rot;\n        int ndir;\n        int pri;\n    };\n\n    struct MatchResult {\n        int cnt = 0;\n        int priSum = 0;\n        vector<char> rot;\n        vector<char> act;\n        MatchResult() {}\n        MatchResult(int Vp): rot(Vp, '.'), act(Vp, '.') {}\n    };\n\n    MatchResult buildMatching(Pt newRoot, bool wantDrop, const Goal* prefGoal) const {\n        MatchResult res(Vp);\n\n        vector<Pt> cells;\n        vector<vector<Edge>> adj(Vp);\n\n        auto getCellIdx = [&](int x, int y) {\n            for (int i = 0; i < (int)cells.size(); i++) {\n                if (cells[i].x == x && cells[i].y == y) return i;\n            }\n            cells.push_back({x, y});\n            return (int)cells.size() - 1;\n        };\n\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (wantDrop && !holding[leaf]) continue;\n            if (!wantDrop && holding[leaf]) continue;\n\n            vector<pair<int, Edge>> tmp;\n            for (auto [rc, delta] : vector<pair<char,int>>{{'.',0},{'L',-1},{'R',+1}}) {\n                int nd = dirLeaf[leaf];\n                if (delta == -1) nd = (nd + 3) & 3;\n                else if (delta == +1) nd = (nd + 1) & 3;\n\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                if (!inb(x, y)) continue;\n\n                bool ok = wantDrop ? isDeficitCell(x, y) : isSurplusCell(x, y);\n                if (!ok) continue;\n\n                int pri = 0;\n                if (prefGoal && prefGoal->ok &&\n                    prefGoal->leaf == leaf &&\n                    prefGoal->dir == nd &&\n                    prefGoal->rootPos == newRoot &&\n                    prefGoal->cell.x == x && prefGoal->cell.y == y) {\n                    pri += 100;\n                }\n                pri += (rc == '.' ? 2 : 1);\n\n                int ci = getCellIdx(x, y);\n                Edge e{ci, rc, nd, pri};\n\n                bool found = false;\n                for (auto &pe : tmp) {\n                    if (pe.first == ci) {\n                        if (e.pri > pe.second.pri) pe.second = e;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) tmp.push_back({ci, e});\n            }\n\n            for (auto &pe : tmp) adj[leaf].push_back(pe.second);\n            sort(adj[leaf].begin(), adj[leaf].end(), [&](const Edge& a, const Edge& b){\n                return a.pri > b.pri;\n            });\n        }\n\n        int C = (int)cells.size();\n        vector<int> matchCell(C, -1);\n        vector<int> matchEdge(C, -1);\n\n        vector<int> order;\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (wantDrop && !holding[leaf]) continue;\n            if (!wantDrop && holding[leaf]) continue;\n            order.push_back(leaf);\n        }\n        sort(order.begin(), order.end(), [&](int a, int b){\n            if (adj[a].size() != adj[b].size()) return adj[a].size() < adj[b].size();\n            int ma = adj[a].empty() ? -1 : adj[a][0].pri;\n            int mb = adj[b].empty() ? -1 : adj[b][0].pri;\n            if (ma != mb) return ma > mb;\n            return a < b;\n        });\n\n        function<bool(int, vector<char>&)> dfs = [&](int u, vector<char>& vis) -> bool {\n            for (int ei = 0; ei < (int)adj[u].size(); ei++) {\n                int c = adj[u][ei].cellIdx;\n                if (vis[c]) continue;\n                vis[c] = 1;\n                if (matchCell[c] == -1 || dfs(matchCell[c], vis)) {\n                    matchCell[c] = u;\n                    matchEdge[c] = ei;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int leaf : order) {\n            vector<char> vis(C, 0);\n            if (dfs(leaf, vis)) res.cnt++;\n        }\n\n        for (int c = 0; c < C; c++) {\n            if (matchCell[c] == -1) continue;\n            int leaf = matchCell[c];\n            const Edge& e = adj[leaf][matchEdge[c]];\n            res.rot[leaf] = e.rot;\n            res.act[leaf] = 'P';\n            res.priSum += e.pri;\n        }\n\n        return res;\n    }\n\n    long long evaluateMove(char mv, const Goal& gp, const Goal& gd, bool preferDrop,\n                           MatchResult* outDrop, MatchResult* outPick) const\n    {\n        Pt nr = moveRoot(root, mv);\n        MatchResult dropRes = buildMatching(nr, true, preferDrop ? &gd : nullptr);\n        MatchResult pickRes = buildMatching(nr, false, preferDrop ? nullptr : &gp);\n\n        int primaryCnt = preferDrop ? dropRes.cnt : pickRes.cnt;\n        int secondaryCnt = preferDrop ? pickRes.cnt : dropRes.cnt;\n        int primaryPri = preferDrop ? dropRes.priSum : pickRes.priSum;\n        int secondaryPri = preferDrop ? pickRes.priSum : dropRes.priSum;\n\n        const Goal& mainGoal = preferDrop ? gd : gp;\n        const Goal& subGoal  = preferDrop ? gp : gd;\n\n        long long score = 0;\n        score += 1LL * primaryCnt * 1000000;\n        score += 1LL * secondaryCnt * 20000;\n        score += 1LL * primaryPri * 200;\n        score += 1LL * secondaryPri * 20;\n\n        if (mainGoal.ok) {\n            int d = abs(nr.x - mainGoal.rootPos.x) + abs(nr.y - mainGoal.rootPos.y);\n            score -= 100LL * d;\n        } else if (subGoal.ok) {\n            int d = abs(nr.x - subGoal.rootPos.x) + abs(nr.y - subGoal.rootPos.y);\n            score -= 100LL * d;\n        }\n\n        if (mv == '.' && (primaryCnt + secondaryCnt) > 0) score += 5;\n\n        if (outDrop) *outDrop = std::move(dropRes);\n        if (outPick) *outPick = std::move(pickRes);\n        return score;\n    }\n\n    void appendCommand(char mv, const vector<char>& rot, const vector<char>& act) {\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        for (int i = 1; i <= K; i++) {\n            cmd[i] = rot[i];\n            cmd[Vp + i] = act[i];\n        }\n        ops.push_back(cmd);\n    }\n\n    char chooseSimpleMoveToward(Pt goalPos) const {\n        int dx = goalPos.x - root.x;\n        int dy = goalPos.y - root.y;\n        if (abs(dx) >= abs(dy)) {\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n        } else {\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n        }\n        return '.';\n    }\n\n    void actOneGoal(const Goal& g, bool wantDrop) {\n        int leaf = g.leaf;\n        while (true) {\n            if ((int)ops.size() >= 100000 || (int)ops.size() >= cutoffTurns) return;\n\n            char mv = chooseSimpleMoveToward(g.rootPos);\n            char rc = oneStepRotToward(dirLeaf[leaf], g.dir);\n\n            Pt nr = moveRoot(root, mv);\n            int nd = applyRot(dirLeaf[leaf], rc);\n            bool canAct = (nr == g.rootPos && nd == g.dir);\n\n            vector<char> rot(Vp, '.');\n            vector<char> act(Vp, '.');\n            rot[leaf] = rc;\n            if (canAct) act[leaf] = 'P';\n\n            appendCommand(mv, rot, act);\n\n            root = nr;\n            dirLeaf[leaf] = nd;\n\n            if (canAct) {\n                if (wantDrop) {\n                    int id = P.did[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveD[id] && holding[leaf]) {\n                        aliveD[id] = false;\n                        remD--;\n                        holding[leaf] = false;\n                        holdCnt--;\n                    }\n                } else {\n                    int id = P.sid[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveS[id] && !holding[leaf]) {\n                        aliveS[id] = false;\n                        remS--;\n                        holding[leaf] = true;\n                        holdCnt++;\n                    }\n                }\n                break;\n            }\n        }\n    }\n\n    SimResult run() {\n        int noActionStreak = 0;\n\n        while ((remD > 0 || holdCnt > 0) &&\n               (int)ops.size() < 100000 &&\n               (int)ops.size() < cutoffTurns)\n        {\n            Goal gp = findGoal(false);\n            Goal gd = findGoal(true);\n            if (!gp.ok && !gd.ok) break;\n\n            bool preferDrop = chooseMode(gp, gd);\n\n            vector<char> legalMoves = {'.', 'U', 'D', 'L', 'R'};\n            long long bestScore = LLONG_MIN;\n            char bestMv = '.';\n            MatchResult bestDrop(Vp), bestPick(Vp);\n\n            for (char mv : legalMoves) {\n                Pt nr = moveRoot(root, mv);\n                if (!inb(nr.x, nr.y)) continue;\n\n                MatchResult dr(Vp), pr(Vp);\n                long long sc = evaluateMove(mv, gp, gd, preferDrop, &dr, &pr);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestMv = mv;\n                    bestDrop = std::move(dr);\n                    bestPick = std::move(pr);\n                }\n            }\n\n            Pt newRoot = moveRoot(root, bestMv);\n            vector<char> rot(Vp, '.');\n            vector<char> act(Vp, '.');\n\n            for (int leaf = 1; leaf <= K; leaf++) {\n                if (bestDrop.act[leaf] == 'P') {\n                    rot[leaf] = bestDrop.rot[leaf];\n                    act[leaf] = 'P';\n                }\n            }\n            for (int leaf = 1; leaf <= K; leaf++) {\n                if (act[leaf] == '.' && bestPick.act[leaf] == 'P') {\n                    rot[leaf] = bestPick.rot[leaf];\n                    act[leaf] = 'P';\n                }\n            }\n\n            const Goal& mainGoal = preferDrop ? gd : gp;\n            if (mainGoal.ok && act[mainGoal.leaf] == '.') {\n                rot[mainGoal.leaf] = oneStepRotToward(dirLeaf[mainGoal.leaf], mainGoal.dir);\n            }\n\n            appendCommand(bestMv, rot, act);\n\n            bool didAction = false;\n            root = newRoot;\n            for (int leaf = 1; leaf <= K; leaf++) {\n                dirLeaf[leaf] = applyRot(dirLeaf[leaf], rot[leaf]);\n            }\n\n            for (int leaf = 1; leaf <= K; leaf++) {\n                if (act[leaf] != 'P') continue;\n                int x = root.x + DX[dirLeaf[leaf]] * len[leaf];\n                int y = root.y + DY[dirLeaf[leaf]] * len[leaf];\n                if (!inb(x, y)) continue;\n\n                if (holding[leaf]) {\n                    int id = P.did[x][y];\n                    if (id != -1 && aliveD[id]) {\n                        aliveD[id] = false;\n                        remD--;\n                        holding[leaf] = false;\n                        holdCnt--;\n                        didAction = true;\n                    }\n                } else {\n                    int id = P.sid[x][y];\n                    if (id != -1 && aliveS[id]) {\n                        aliveS[id] = false;\n                        remS--;\n                        holding[leaf] = true;\n                        holdCnt++;\n                        didAction = true;\n                    }\n                }\n            }\n\n            if (didAction) noActionStreak = 0;\n            else noActionStreak++;\n\n            if (noActionStreak > 5 * N + 60) break;\n        }\n\n        while ((remD > 0 || holdCnt > 0) &&\n               (int)ops.size() < 100000 &&\n               (int)ops.size() < cutoffTurns)\n        {\n            bool wantDrop = (holdCnt > 0);\n            Goal g = findGoal(wantDrop);\n            if (!g.ok) break;\n            actOneGoal(g, wantDrop);\n        }\n\n        SimResult res;\n        res.initialRoot = initialRoot;\n        res.len = len;\n        res.ops = ops;\n        res.complete = (remD == 0 && holdCnt == 0);\n        res.turns = res.complete ? (int)ops.size() : (int)1e9;\n        return res;\n    }\n};\n\nstatic vector<vector<int>> generateDesigns(int K, int N) {\n    vector<vector<int>> designs;\n    auto add = [&](vector<int> a) {\n        if ((int)a.size() != K + 1) return;\n        for (int i = 1; i <= K; i++) a[i] = max(1, min(N - 1, a[i]));\n        for (auto &b : designs) if (b == a) return;\n        designs.push_back(a);\n    };\n\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        add(a);\n    }\n    {\n        int R = max(1, min(3, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        int R = max(1, min(4, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        int R = max(1, min(5, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) / 2;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = i;\n        add(a);\n    }\n\n    return designs;\n}\n\nstatic vector<Pt> generateRoots(const Problem& P) {\n    vector<Pt> roots;\n    auto add = [&](Pt p) {\n        p.x = max(0, min(P.N - 1, p.x));\n        p.y = max(0, min(P.N - 1, p.y));\n        for (auto &q : roots) if (q == p) return;\n        roots.push_back(p);\n    };\n\n    add(P.medianAll());\n    add(P.centroidAll());\n    add(P.center());\n\n    return roots;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem P;\n    cin >> P.N >> P.M >> P.Vmax;\n    P.s.resize(P.N);\n    P.t.resize(P.N);\n    for (int i = 0; i < P.N; i++) cin >> P.s[i];\n    for (int i = 0; i < P.N; i++) cin >> P.t[i];\n\n    P.sid.assign(P.N, vector<int>(P.N, -1));\n    P.did.assign(P.N, vector<int>(P.N, -1));\n\n    for (int i = 0; i < P.N; i++) {\n        for (int j = 0; j < P.N; j++) {\n            if (P.s[i][j] == '1' && P.t[i][j] == '0') {\n                P.sid[i][j] = (int)P.surplusCells.size();\n                P.surplusCells.push_back({i, j});\n            }\n            if (P.s[i][j] == '0' && P.t[i][j] == '1') {\n                P.did[i][j] = (int)P.deficitCells.size();\n                P.deficitCells.push_back({i, j});\n            }\n        }\n    }\n\n    int K = P.Vmax - 1;\n    auto designs = generateDesigns(K, P.N);\n    auto roots = generateRoots(P);\n\n    SimResult best;\n    int cutoff = 1000000000;\n\n    for (const auto& root : roots) {\n        for (const auto& len : designs) {\n            Simulator sim(P, len, root, cutoff);\n            SimResult cur = sim.run();\n            if (cur.complete && cur.turns < best.turns) {\n                best = std::move(cur);\n                cutoff = best.turns;\n            }\n        }\n    }\n\n    if (!best.complete) {\n        Simulator sim(P, designs[0], roots[0], 1000000000);\n        best = sim.run();\n    }\n\n    int Vp = K + 1;\n    cout << Vp << '\\n';\n    for (int i = 1; i <= K; i++) {\n        cout << 0 << ' ' << best.len[i] << '\\n';\n    }\n    cout << best.initialRoot.x << ' ' << best.initialRoot.y << '\\n';\n    for (auto &cmd : best.ops) cout << cmd << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Point {\n    int x, y;\n};\nstruct WPoint {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Candidate {\n    vector<Point> poly;\n    int approx = INT_MIN / 4;\n};\n\nstatic inline uint64_t pack_xy(int x, int y) {\n    return (uint64_t(uint32_t(x)) << 32) | uint32_t(y);\n}\n\nstatic inline bool on_segment(const Point& p, const Point& a, const Point& b) {\n    if (a.x == b.x) {\n        if (p.x != a.x) return false;\n        return min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);\n    } else if (a.y == b.y) {\n        if (p.y != a.y) return false;\n        return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x);\n    }\n    return false;\n}\n\nstatic bool inside_polygon_inclusive(const Point& p, const vector<Point>& poly) {\n    bool in = false;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        Point a = poly[i];\n        Point b = poly[(i + 1) % n];\n\n        if (on_segment(p, a, b)) return true;\n\n        // Ray casting to +x, for vertical edges only\n        if (a.x == b.x) {\n            if (a.y > b.y) swap(a, b);\n            if (a.y <= p.y && p.y < b.y && p.x < a.x) {\n                in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int exact_diff(const vector<Point>& poly, const vector<WPoint>& pts) {\n    if (poly.empty()) return INT_MIN / 4;\n\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    for (auto &q : poly) {\n        minx = min(minx, q.x);\n        maxx = max(maxx, q.x);\n        miny = min(miny, q.y);\n        maxy = max(maxy, q.y);\n    }\n\n    int diff = 0;\n    for (auto &pt : pts) {\n        if (pt.x < minx || pt.x > maxx || pt.y < miny || pt.y > maxy) continue;\n        if (inside_polygon_inclusive(Point{pt.x, pt.y}, poly)) diff += pt.w;\n    }\n    return diff;\n}\n\nstatic long long polygon_perimeter(const vector<Point>& poly) {\n    long long per = 0;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % n];\n        per += llabs((long long)a.x - b.x) + llabs((long long)a.y - b.y);\n    }\n    return per;\n}\n\nstatic vector<Point> fallback_polygon(const unordered_set<uint64_t>& occ) {\n    for (int x = 0; x <= 200; x++) {\n        for (int y = 0; y <= 200; y++) {\n            if (!occ.count(pack_xy(x, y)) &&\n                !occ.count(pack_xy(x + 1, y)) &&\n                !occ.count(pack_xy(x, y + 1)) &&\n                !occ.count(pack_xy(x + 1, y + 1))) {\n                return {\n                    {x, y},\n                    {x + 1, y},\n                    {x + 1, y + 1},\n                    {x, y + 1}\n                };\n            }\n        }\n    }\n    return {{0,0},{1,0},{1,1},{0,1}};\n}\n\nstatic vector<int> build_lines(int S, int offset) {\n    vector<int> v;\n    v.push_back(0);\n    for (int x = offset; x < 100000; x += S) {\n        if (x > 0) v.push_back(x);\n    }\n    if (v.back() != 100000) v.push_back(100000);\n    sort(v.begin(), v.end());\n    v.erase(unique(v.begin(), v.end()), v.end());\n    return v;\n}\n\nstatic int find_cell(const vector<int>& lines, int coord) {\n    int idx = int(upper_bound(lines.begin(), lines.end(), coord) - lines.begin()) - 1;\n    if (idx < 0) idx = 0;\n    if (idx >= (int)lines.size() - 1) idx = (int)lines.size() - 2;\n    return idx;\n}\n\nstatic vector<char> solve_selection_by_cut(const vector<int>& cell_w, int W, int H, int lambda) {\n    if (lambda == 0) {\n        vector<char> sel(W * H, 0);\n        for (int i = 0; i < W * H; i++) {\n            if (cell_w[i] > 0) sel[i] = 1;\n        }\n        return sel;\n    }\n\n    int SRC = W * H;\n    int SNK = W * H + 1;\n    mf_graph<int> g(W * H + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int outside_sides = 0;\n            if (x == 0) outside_sides++;\n            if (x == W - 1) outside_sides++;\n            if (y == 0) outside_sides++;\n            if (y == H - 1) outside_sides++;\n\n            int u = cell_w[v] - lambda * outside_sides;\n            if (u >= 0) g.add_edge(SRC, v, u);\n            else g.add_edge(v, SNK, -u);\n\n            if (x + 1 < W) {\n                int to = id(x + 1, y);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n            if (y + 1 < H) {\n                int to = id(x, y + 1);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n        }\n    }\n\n    g.flow(SRC, SNK);\n    auto cut = g.min_cut(SRC);\n    vector<char> sel(W * H, 0);\n    for (int i = 0; i < W * H; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nstatic void fill_holes(vector<char>& sel, int W, int H) {\n    vector<char> vis(W * H, 0);\n    queue<int> q;\n\n    auto push_if = [&](int x, int y) {\n        int id = y * W + x;\n        if (!sel[id] && !vis[id]) {\n            vis[id] = 1;\n            q.push(id);\n        }\n    };\n\n    for (int x = 0; x < W; x++) {\n        push_if(x, 0);\n        push_if(x, H - 1);\n    }\n    for (int y = 0; y < H; y++) {\n        push_if(0, y);\n        push_if(W - 1, y);\n    }\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx[d], ny = y + dy[d];\n            if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n            int nid = ny * W + nx;\n            if (!sel[nid] && !vis[nid]) {\n                vis[nid] = 1;\n                q.push(nid);\n            }\n        }\n    }\n\n    for (int i = 0; i < W * H; i++) {\n        if (!sel[i] && !vis[i]) sel[i] = 1;\n    }\n}\n\nstatic void cleanup_selection(vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int iter = 0; iter < 2; iter++) {\n        vector<char> nxt = sel;\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int id = y * W + x;\n                int cnt = 0;\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + dx[d], ny = y + dy[d];\n                    if (0 <= nx && nx < W && 0 <= ny && ny < H) {\n                        cnt += sel[ny * W + nx];\n                    }\n                }\n                if (sel[id]) {\n                    if (cnt <= 1 && cell_w[id] <= 0) nxt[id] = 0;\n                } else {\n                    if (cnt >= 3 && cell_w[id] > 0) nxt[id] = 1;\n                }\n            }\n        }\n        sel.swap(nxt);\n    }\n}\n\nstruct Component {\n    vector<int> cells;\n    int approx = 0;\n};\n\nstatic vector<Component> get_components(const vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    vector<char> vis(W * H, 0);\n    vector<Component> comps;\n    queue<int> q;\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int s = 0; s < W * H; s++) {\n        if (!sel[s] || vis[s]) continue;\n        vis[s] = 1;\n        q.push(s);\n        Component c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            c.approx += cell_w[v];\n            int x = v % W, y = v / W;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n                int nid = ny * W + nx;\n                if (sel[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        comps.push_back(move(c));\n    }\n\n    sort(comps.begin(), comps.end(), [](const Component& a, const Component& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        return a.cells.size() > b.cells.size();\n    });\n    return comps;\n}\n\nstruct PolyInfo {\n    vector<Point> poly;\n    bool ok = false;\n};\n\nstatic PolyInfo build_polygon_from_component(\n    const vector<char>& comp_sel, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    PolyInfo res;\n    int GW = W + 1;\n    int GH = H + 1;\n    int GV = GW * GH;\n    vector<int> nxt(GV, -1);\n    int edge_cnt = 0;\n\n    auto vid = [&](int x, int y) { return y * GW + x; };\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) -> bool {\n        int a = vid(x1, y1);\n        int b = vid(x2, y2);\n        if (nxt[a] != -1) return false;\n        nxt[a] = b;\n        edge_cnt++;\n        return true;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int id = y * W + x;\n            if (!comp_sel[id]) continue;\n\n            if (y == 0 || !comp_sel[(y - 1) * W + x]) {\n                if (!add_edge(x, y, x + 1, y)) return res;\n            }\n            if (x == W - 1 || !comp_sel[y * W + (x + 1)]) {\n                if (!add_edge(x + 1, y, x + 1, y + 1)) return res;\n            }\n            if (y == H - 1 || !comp_sel[(y + 1) * W + x]) {\n                if (!add_edge(x + 1, y + 1, x, y + 1)) return res;\n            }\n            if (x == 0 || !comp_sel[y * W + (x - 1)]) {\n                if (!add_edge(x, y + 1, x, y)) return res;\n            }\n        }\n    }\n\n    if (edge_cnt == 0) return res;\n\n    int start = -1;\n    for (int i = 0; i < GV; i++) {\n        if (nxt[i] != -1) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return res;\n\n    vector<int> cyc;\n    int cur = start;\n    for (int step = 0; step <= edge_cnt + 5; step++) {\n        cyc.push_back(cur);\n        cur = nxt[cur];\n        if (cur == -1) return res;\n        if (cur == start) break;\n    }\n    if (cur != start) return res;\n    if ((int)cyc.size() != edge_cnt) return res;\n\n    auto dec = [&](int v) -> pair<int,int> {\n        return {v % GW, v / GW};\n    };\n    auto dir = [&](int a, int b) -> pair<int,int> {\n        auto [x1, y1] = dec(a);\n        auto [x2, y2] = dec(b);\n        return {(x2 > x1) - (x2 < x1), (y2 > y1) - (y2 < y1)};\n    };\n\n    vector<Point> poly;\n    int n = (int)cyc.size();\n    for (int i = 0; i < n; i++) {\n        int pv = cyc[(i - 1 + n) % n];\n        int cv = cyc[i];\n        int nv = cyc[(i + 1) % n];\n        if (dir(pv, cv) != dir(cv, nv)) {\n            auto [gx, gy] = dec(cv);\n            poly.push_back({xs[gx], ys[gy]});\n        }\n    }\n\n    if ((int)poly.size() < 4) return res;\n    res.poly = move(poly);\n    res.ok = true;\n    return res;\n}\n\nstatic bool legal_polygon(const vector<Point>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    long long per = polygon_perimeter(poly);\n    if (per > 400000LL) return false;\n    for (auto &p : poly) {\n        if (p.x < 0 || p.x > 100000 || p.y < 0 || p.y > 100000) return false;\n    }\n    set<pair<int,int>> st;\n    for (auto &p : poly) {\n        if (!st.insert({p.x, p.y}).second) return false;\n    }\n    return true;\n}\n\nstatic Candidate max_sum_rectangle_candidate(\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    vector<int> acc(H);\n\n    for (int l = 0; l < W; l++) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int r = l; r < W; r++) {\n            for (int y = 0; y < H; y++) acc[y] += cell_w[y * W + r];\n\n            int cur = 0, start = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = acc[y];\n                    start = y;\n                } else {\n                    cur += acc[y];\n                }\n                if (cur > best.approx) {\n                    int x1 = xs[l], x2 = xs[r + 1];\n                    int y1 = ys[start], y2 = ys[y + 1];\n                    if (x1 < x2 && y1 < y2) {\n                        vector<Point> poly = {\n                            {x1, y1},\n                            {x2, y1},\n                            {x2, y2},\n                            {x1, y2}\n                        };\n                        if (legal_polygon(poly)) {\n                            best.approx = cur;\n                            best.poly = move(poly);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<WPoint> pts;\n    pts.reserve(2 * N);\n    unordered_set<uint64_t> occ;\n    occ.reserve(4 * N);\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, +1});\n        occ.insert(pack_xy(x, y));\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, -1});\n        occ.insert(pack_xy(x, y));\n    }\n\n    vector<Point> best_poly = fallback_polygon(occ);\n    int best_diff = exact_diff(best_poly, pts);\n\n    vector<Candidate> cands;\n\n    auto add_candidate = [&](const vector<Point>& poly, int approx) {\n        if (!legal_polygon(poly)) return;\n        cands.push_back({poly, approx});\n    };\n\n    const vector<int> sizes = {1000, 750, 500};\n\n    for (int S : sizes) {\n        vector<int> offsets = {0};\n        if (S / 2 > 0) offsets.push_back(S / 2);\n\n        vector<int> lambdas;\n        if (S >= 900) lambdas = {0, 1, 2, 4, 8, 12};\n        else if (S >= 700) lambdas = {0, 1, 2, 3, 5, 8};\n        else lambdas = {0, 1, 2, 3, 4, 6};\n\n        for (int off : offsets) {\n            vector<int> xs = build_lines(S, off);\n            vector<int> ys = build_lines(S, off);\n            int W = (int)xs.size() - 1;\n            int H = (int)ys.size() - 1;\n\n            vector<int> cell_w(W * H, 0);\n            for (auto &p : pts) {\n                int gx = find_cell(xs, p.x);\n                int gy = find_cell(ys, p.y);\n                cell_w[gy * W + gx] += p.w;\n            }\n\n            // Rectangle candidate\n            {\n                Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n                if (!rect.poly.empty()) cands.push_back(rect);\n            }\n\n            for (int lambda : lambdas) {\n                vector<char> sel = solve_selection_by_cut(cell_w, W, H, lambda);\n\n                bool any = false;\n                for (char c : sel) if (c) { any = true; break; }\n                if (!any) continue;\n\n                // base variant\n                vector<char> base = sel;\n                fill_holes(base, W, H);\n\n                // cleaned variant\n                vector<char> cleaned = base;\n                cleanup_selection(cleaned, cell_w, W, H);\n                fill_holes(cleaned, W, H);\n\n                vector<vector<char>> variants;\n                variants.push_back(base);\n                variants.push_back(cleaned);\n\n                for (auto &cur_sel : variants) {\n                    auto comps = get_components(cur_sel, cell_w, W, H);\n                    int K = min(6, (int)comps.size());\n                    for (int ci = 0; ci < K; ci++) {\n                        vector<char> comp_sel(W * H, 0);\n                        for (int v : comps[ci].cells) comp_sel[v] = 1;\n\n                        PolyInfo info = build_polygon_from_component(comp_sel, W, H, xs, ys);\n                        if (!info.ok) continue;\n                        if (!legal_polygon(info.poly)) continue;\n\n                        cands.push_back({info.poly, comps[ci].approx});\n                    }\n                }\n            }\n        }\n    }\n\n    // Sort by approximate score and evaluate exact score only for top candidates\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.poly.size() != b.poly.size()) return a.poly.size() < b.poly.size();\n        return polygon_perimeter(a.poly) < polygon_perimeter(b.poly);\n    });\n\n    // light dedup by hash\n    vector<Candidate> filtered;\n    unordered_set<uint64_t> seen;\n    seen.reserve(cands.size() * 2 + 1);\n\n    auto hash_poly = [&](const vector<Point>& poly) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (auto &p : poly) {\n            h ^= uint64_t(uint32_t(p.x)) * 1000003ULL + uint32_t(p.y);\n            h *= 1099511628211ULL;\n        }\n        h ^= poly.size();\n        return h;\n    };\n\n    for (auto &c : cands) {\n        uint64_t h = hash_poly(c.poly);\n        if (seen.insert(h).second) filtered.push_back(move(c));\n    }\n\n    int LIMIT = min(40, (int)filtered.size());\n    for (int i = 0; i < LIMIT; i++) {\n        int diff = exact_diff(filtered[i].poly, pts);\n        if (diff > best_diff) {\n            best_diff = diff;\n            best_poly = filtered[i].poly;\n        }\n    }\n\n    cout << best_poly.size() << '\\n';\n    for (auto &p : best_poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing ld = long double;\n\nstruct Op {\n    int p, r;\n    char d;\n    int b;\n};\n\nstruct Placed {\n    ll x = 0, y = 0, w = 0, h = 0;\n    bool used = false;\n};\n\nstruct Candidate {\n    ll estW = 0, estH = 0, est = 0;\n    bool isRow = true;\n    int anchorStrategy = 0;\n    vector<Op> ops;\n    string sig;\n};\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nint N, T, sigma_;\nvector<ll> obsW, obsH;\n\nbool overlap1D(ll l1, ll r1, ll l2, ll r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nvoid place_one(int p, int r, char d, int b, const vector<ll>& baseW, const vector<ll>& baseH,\n               vector<Placed>& placed, ll& W, ll& H) {\n    ll w = (r == 0 ? baseW[p] : baseH[p]);\n    ll h = (r == 0 ? baseH[p] : baseW[p]);\n\n    ll x = 0, y = 0;\n    if (d == 'U') {\n        x = (b == -1 ? 0 : placed[b].x + placed[b].w);\n        y = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(x, x + w, placed[i].x, placed[i].x + placed[i].w)) {\n                y = max(y, placed[i].y + placed[i].h);\n            }\n        }\n    } else { // 'L'\n        y = (b == -1 ? 0 : placed[b].y + placed[b].h);\n        x = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(y, y + h, placed[i].y, placed[i].y + placed[i].h)) {\n                x = max(x, placed[i].x + placed[i].w);\n            }\n        }\n    }\n\n    placed[p] = {x, y, w, h, true};\n    W = max(W, x + w);\n    H = max(H, y + h);\n}\n\npair<ll,ll> simulate_ops(const vector<Op>& ops, const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<Placed> placed(N);\n    ll W = 0, H = 0;\n    for (const auto& op : ops) {\n        place_one(op.p, op.r, op.d, op.b, baseW, baseH, placed, W, H);\n    }\n    return {W, H};\n}\n\nstring ops_signature(const vector<Op>& ops) {\n    string s;\n    s.reserve(ops.size() * 6);\n    for (const auto& op : ops) {\n        s.push_back(char('0' + op.r));\n        s.push_back(op.d);\n        int x = op.b + 1; // 0..N\n        s.push_back(char('A' + (x / 26)));\n        s.push_back(char('A' + (x % 26)));\n    }\n    return s;\n}\n\nvector<pair<int,int>> partition_strip(const vector<ll>& primary, const vector<ll>& secondary, ll cap) {\n    vector<ll> dp(N + 1, INF64);\n    vector<int> cnt(N + 1, INT_MAX);\n    vector<int> prv(N + 1, -1);\n    dp[0] = 0;\n    cnt[0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        if (dp[i] >= INF64 / 2) continue;\n        ll sumP = 0;\n        ll mxS = 0;\n        for (int j = i; j < N; j++) {\n            sumP += primary[j];\n            if (sumP > cap) break;\n            mxS = max(mxS, secondary[j]);\n\n            ll ndp = dp[i] + mxS;\n            int ncnt = cnt[i] + 1;\n            if (ndp < dp[j + 1] || (ndp == dp[j + 1] && ncnt < cnt[j + 1])) {\n                dp[j + 1] = ndp;\n                cnt[j + 1] = ncnt;\n                prv[j + 1] = i;\n            }\n        }\n    }\n\n    if (prv[N] == -1) return {};\n\n    vector<pair<int,int>> segs_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = prv[cur];\n        if (p < 0) return {};\n        segs_rev.push_back({p, cur});\n        cur = p;\n    }\n    reverse(segs_rev.begin(), segs_rev.end());\n    return segs_rev;\n}\n\nstring make_signature(bool isRow, int strategy, const vector<int>& rot, const vector<pair<int,int>>& segs) {\n    string s;\n    s.reserve(2 + N + 1 + N);\n    s.push_back(isRow ? 'R' : 'C');\n    s.push_back(char('0' + strategy));\n    for (int i = 0; i < N; i++) s.push_back(char('0' + rot[i]));\n    s.push_back('|');\n    vector<char> br(N, '0');\n    for (auto [l, r] : segs) br[r - 1] = '1';\n    for (int i = 0; i < N; i++) s.push_back(br[i]);\n    return s;\n}\n\nCandidate build_row_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& baseW, const vector<ll>& baseH) {\n    Candidate c;\n    c.isRow = true;\n    c.anchorStrategy = strategy;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto bottom = [&](int idx) -> ll {\n        return placed[idx].y + placed[idx].h;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'U', -1});\n            place_one(l, rot[l], 'U', -1, baseW, baseH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'L', b});\n            place_one(l, rot[l], 'L', b, baseW, baseH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'U', i - 1});\n            place_one(i, rot[i], 'U', i - 1, baseW, baseH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (bottom(i) > bottom(prevMax)) prevMax = i;\n            if (bottom(i) < bottom(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || bottom(prevMax) > bottom(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || bottom(prevMin) < bottom(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nCandidate build_col_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& baseW, const vector<ll>& baseH) {\n    Candidate c;\n    c.isRow = false;\n    c.anchorStrategy = strategy;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto right = [&](int idx) -> ll {\n        return placed[idx].x + placed[idx].w;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'L', -1});\n            place_one(l, rot[l], 'L', -1, baseW, baseH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'U', b});\n            place_one(l, rot[l], 'U', b, baseW, baseH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'L', i - 1});\n            place_one(i, rot[i], 'L', i - 1, baseW, baseH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (right(i) > right(prevMax)) prevMax = i;\n            if (right(i) < right(prevMin)) prevMin = i;\n        }\n\n        if (globalMax == -1 || right(prevMax) > right(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || right(prevMin) < right(globalMin)) globalMin = prevMin;\n    }\n\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.ops = move(ops);\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nvector<ll> generate_caps(const vector<ll>& primary, const vector<ll>& secondary) {\n    ll total = 0, mx = 0;\n    ld area = 0;\n    for (int i = 0; i < N; i++) {\n        total += primary[i];\n        mx = max(mx, primary[i]);\n        area += (ld)primary[i] * (ld)secondary[i];\n    }\n\n    vector<ll> vals;\n    vals.push_back(mx);\n\n    static const ld mults1[] = {0.72L, 0.85L, 1.00L, 1.15L, 1.35L};\n    int K = min(N, 16);\n    for (int k = 1; k <= K; k++) {\n        ld base = (ld)total / (ld)k;\n        for (ld m : mults1) {\n            ll v = (ll)llround(base * m);\n            vals.push_back(max(mx, v));\n        }\n    }\n\n    ld sq = sqrt(area);\n    static const ld mults2[] = {0.55L, 0.70L, 0.85L, 1.00L, 1.20L, 1.45L, 1.80L};\n    for (ld m : mults2) {\n        ll v = (ll)llround(sq * m);\n        vals.push_back(max(mx, v));\n    }\n\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end()), vals.end());\n\n    if ((int)vals.size() > 40) {\n        vector<ll> sampled;\n        sampled.reserve(40);\n        for (int i = 0; i < 40; i++) {\n            int idx = (int)((ld)i * (ld)(vals.size() - 1) / 39.0L);\n            if (sampled.empty() || sampled.back() != vals[idx]) sampled.push_back(vals[idx]);\n        }\n        vals = move(sampled);\n    }\n\n    return vals;\n}\n\nvector<vector<int>> generate_rotation_modes(const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<vector<int>> modes;\n    unordered_set<string> seen;\n\n    auto add_mode = [&](const vector<int>& rot) {\n        string s;\n        s.reserve(N);\n        for (int b : rot) s.push_back(char('0' + b));\n        if (seen.insert(s).second) modes.push_back(rot);\n    };\n\n    vector<int> all0(N, 0), all1(N, 1), minW(N), minH(N);\n    for (int i = 0; i < N; i++) {\n        minW[i] = (baseW[i] <= baseH[i] ? 0 : 1);\n        minH[i] = (baseH[i] <= baseW[i] ? 0 : 1);\n    }\n\n    add_mode(all0);\n    add_mode(all1);\n    add_mode(minW);\n    add_mode(minH);\n\n    vector<ll> mxs(N);\n    for (int i = 0; i < N; i++) mxs[i] = max(baseW[i], baseH[i]);\n    vector<ll> sortedMx = mxs;\n    sort(sortedMx.begin(), sortedMx.end());\n    ll th1 = sortedMx[N / 2];\n    ll th2 = sortedMx[(3 * N) / 4];\n\n    vector<int> hy1(N), hy2(N), hy3(N);\n    for (int i = 0; i < N; i++) {\n        hy1[i] = (mxs[i] >= th1 ? minW[i] : minH[i]);\n        hy2[i] = (mxs[i] >= th2 ? minW[i] : minH[i]);\n        hy3[i] = (mxs[i] >= th1 ? minH[i] : minW[i]);\n    }\n    add_mode(hy1);\n    add_mode(hy2);\n    add_mode(hy3);\n\n    ll near_thr = 2LL * sigma_;\n    vector<vector<int>> bases = {minW, minH, hy1, hy2};\n\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int seed = 0; seed < 2; seed++) {\n            vector<int> rot = bases[bi];\n            mt19937 rng(1234567 + 1009 * bi + seed);\n            for (int i = 0; i < N; i++) {\n                if (llabs(baseW[i] - baseH[i]) <= near_thr) {\n                    if (rng() & 1) rot[i] ^= 1;\n                }\n            }\n            add_mode(rot);\n        }\n    }\n\n    return modes;\n}\n\nCandidate improve_rotations(Candidate best, const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<int> pos(N, -1);\n    for (int i = 0; i < (int)best.ops.size(); i++) pos[best.ops[i].p] = i;\n\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        ll sa = baseW[a] + baseH[a];\n        ll sb = baseW[b] + baseH[b];\n        ll da = llabs(baseW[a] - baseH[a]);\n        ll db = llabs(baseW[b] - baseH[b]);\n        if (sa != sb) return sa > sb;\n        return da < db;\n    });\n\n    auto better = [&](ll W1, ll H1, ll W2, ll H2) {\n        if (W1 + H1 != W2 + H2) return W1 + H1 < W2 + H2;\n        return max(W1, H1) < max(W2, H2);\n    };\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (int p : ord) {\n            int idx = pos[p];\n            if (idx < 0) continue;\n\n            vector<Op> ops2 = best.ops;\n            ops2[idx].r ^= 1;\n            auto [W2, H2] = simulate_ops(ops2, baseW, baseH);\n            if (better(W2, H2, best.estW, best.estH)) {\n                best.ops.swap(ops2);\n                best.estW = W2;\n                best.estH = H2;\n                best.est = W2 + H2;\n                best.sig = ops_signature(best.ops);\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n    return best;\n}\n\nvector<Candidate> generate_candidates(const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<Candidate> cands;\n    unordered_set<string> usedSig;\n\n    auto add_candidate = [&](Candidate&& c) {\n        if ((int)c.ops.size() != N) return;\n        c.sig = ops_signature(c.ops);\n        if (usedSig.insert(c.sig).second) {\n            cands.push_back(move(c));\n        }\n    };\n\n    auto rotModes = generate_rotation_modes(baseW, baseH);\n\n    for (const auto& rot : rotModes) {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = (rot[i] == 0 ? baseW[i] : baseH[i]);\n            h[i] = (rot[i] == 0 ? baseH[i] : baseW[i]);\n        }\n\n        {\n            auto caps = generate_caps(w, h);\n            for (ll cap : caps) {\n                auto segs = partition_strip(w, h, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_row_candidate(segs, rot, strat, baseW, baseH));\n                }\n            }\n        }\n\n        {\n            auto caps = generate_caps(h, w);\n            for (ll cap : caps) {\n                auto segs = partition_strip(h, w, cap);\n                if (segs.empty()) continue;\n                for (int strat = 0; strat < 5; strat++) {\n                    add_candidate(build_col_candidate(segs, rot, strat, baseW, baseH));\n                }\n            }\n        }\n    }\n\n    if (cands.empty()) {\n        vector<int> rot(N, 0);\n        vector<pair<int,int>> segs = {{0, N}};\n        add_candidate(build_row_candidate(segs, rot, 0, baseW, baseH));\n        add_candidate(build_col_candidate(segs, rot, 0, baseW, baseH));\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.est != b.est) return a.est < b.est;\n        if (a.estW != b.estW) return a.estW < b.estW;\n        if (a.estH != b.estH) return a.estH < b.estH;\n        return a.sig < b.sig;\n    });\n\n    // Local rotation refinement on top candidates only.\n    int topK = min(16, (int)cands.size());\n    vector<Candidate> extra;\n    for (int i = 0; i < topK; i++) {\n        Candidate imp = improve_rotations(cands[i], baseW, baseH);\n        if (usedSig.insert(imp.sig).second) extra.push_back(move(imp));\n    }\n    for (auto& c : extra) cands.push_back(move(c));\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.est != b.est) return a.est < b.est;\n        if (a.estW != b.estW) return a.estW < b.estW;\n        if (a.estH != b.estH) return a.estH < b.estH;\n        return a.sig < b.sig;\n    });\n\n    return cands;\n}\n\nvoid output_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_;\n    obsW.resize(N);\n    obsH.resize(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    // Conservative adaptive probing:\n    int probeTurns = 0;\n    if (sigma_ >= 3000) probeTurns++;\n    if (sigma_ >= 5500) probeTurns++;\n    if (sigma_ >= 8000) probeTurns++;\n    if (sigma_ >= 9500) probeTurns++;\n    if (T >= 2 * N) probeTurns++;\n    probeTurns = min(probeTurns, max(0, T - 8));\n    probeTurns = min(probeTurns, 5);\n\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        ll ambA = max<ll>(0, 2LL * sigma_ - llabs(obsW[a] - obsH[a]));\n        ll ambB = max<ll>(0, 2LL * sigma_ - llabs(obsW[b] - obsH[b]));\n        ll sa = 2 * (obsW[a] + obsH[a]) + ambA;\n        ll sb = 2 * (obsW[b] + obsH[b]) + ambB;\n        if (sa != sb) return sa > sb;\n        return a < b;\n    });\n\n    vector<ld> sumW(N), sumH(N);\n    vector<int> cnt(N, 1);\n    for (int i = 0; i < N; i++) {\n        sumW[i] = obsW[i];\n        sumH[i] = obsH[i];\n    }\n\n    for (int t = 0; t < probeTurns; t++) {\n        int p = ord[t % N];\n        vector<Op> ops = {{p, 0, 'U', -1}};\n        output_ops(ops);\n\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n\n        sumW[p] += Wm;\n        sumH[p] += Hm;\n        cnt[p]++;\n    }\n\n    vector<ll> estW(N), estH(N);\n    for (int i = 0; i < N; i++) {\n        estW[i] = max<ll>(1, llround(sumW[i] / cnt[i]));\n        estH[i] = max<ll>(1, llround(sumH[i] / cnt[i]));\n    }\n\n    vector<Candidate> candidates = generate_candidates(estW, estH);\n    if (candidates.empty()) return 0;\n\n    vector<char> used(candidates.size(), 0);\n\n    auto best_by = [&](auto fn) -> int {\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = fn(candidates[i]);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    vector<int> initialPlan;\n    {\n        int x;\n\n        x = best_by([&](const Candidate& c) { return (ld)c.est; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) {\n            return c.isRow ? (ld)c.est : 1e99L;\n        });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) {\n            return (!c.isRow) ? (ld)c.est : 1e99L;\n        });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) {\n            return 1.15L * (ld)c.estW + 0.85L * (ld)c.estH;\n        });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) {\n            return 0.85L * (ld)c.estW + 1.15L * (ld)c.estH;\n        });\n        if (x != -1) initialPlan.push_back(x);\n    }\n\n    {\n        vector<int> uniq;\n        vector<char> seen(candidates.size(), 0);\n        for (int x : initialPlan) {\n            if (x >= 0 && !seen[x]) {\n                seen[x] = 1;\n                uniq.push_back(x);\n            }\n        }\n        initialPlan.swap(uniq);\n    }\n\n    ld sumEstW = 0, sumEstH = 0;\n    ld sumMeasW = 0, sumMeasH = 0;\n    const ld prior = 1e6L;\n\n    auto pick_best_adjusted = [&]() -> int {\n        ld scaleW = (sumMeasW + prior) / (sumEstW + prior);\n        ld scaleH = (sumMeasH + prior) / (sumEstH + prior);\n\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = scaleW * (ld)candidates[i].estW + scaleH * (ld)candidates[i].estH;\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    for (int turn = probeTurns; turn < T; turn++) {\n        int localTurn = turn - probeTurns;\n        int idx = -1;\n\n        if (localTurn < (int)initialPlan.size() && !used[initialPlan[localTurn]]) {\n            idx = initialPlan[localTurn];\n        } else {\n            idx = pick_best_adjusted();\n        }\n\n        if (idx == -1) idx = 0;\n        used[idx] = 1;\n\n        output_ops(candidates[idx].ops);\n\n        ll measW, measH;\n        if (!(cin >> measW >> measH)) return 0;\n\n        sumEstW += (ld)candidates[idx].estW;\n        sumEstH += (ld)candidates[idx].estH;\n        sumMeasW += (ld)measW;\n        sumMeasH += (ld)measH;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> X, Y, degv;\n    vector<double> rad;\n\n    mt19937 rng{712367821};\n\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    // ---------- Build/evaluate from permutation ----------\n    long long eval_perm(const vector<int>& perm, vector<int>* out_parent = nullptr) {\n        vector<int> pos(N), depth(N, 0);\n        for (int i = 0; i < N; i++) pos[perm[i]] = i;\n\n        vector<int> parent;\n        if (out_parent) parent.assign(N, -1);\n\n        long long score = 0;\n        for (int i = 0; i < N; i++) {\n            int v = perm[i];\n            int best_d = -1;\n            int best_p = -1;\n\n            for (int u : g[v]) {\n                if (pos[u] < i) {\n                    int du = depth[u];\n                    if (du >= H) continue; // child would exceed H\n                    if (du > best_d) {\n                        best_d = du;\n                        best_p = u;\n                    } else if (du == best_d && best_p != -1) {\n                        // tie-break: prefer low beauty / high degree support\n                        if (A[u] < A[best_p] ||\n                            (A[u] == A[best_p] && degv[u] > degv[best_p])) {\n                            best_p = u;\n                        }\n                    } else if (du == best_d && best_p == -1) {\n                        best_p = u;\n                    }\n                }\n            }\n\n            if (best_p == -1) {\n                depth[v] = 0;\n                if (out_parent) parent[v] = -1;\n            } else {\n                depth[v] = best_d + 1;\n                if (out_parent) parent[v] = best_p;\n            }\n            score += 1LL * (depth[v] + 1) * A[v];\n        }\n\n        if (out_parent) *out_parent = move(parent);\n        return score;\n    }\n\n    vector<int> make_perm_by_key(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_initial_perm(int mode) {\n        vector<double> key(N, 0.0);\n\n        if (mode == 0) {\n            // low beauty first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] + 1e-6 * v;\n            }\n        } else if (mode == 1) {\n            // low beauty, high degree first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] - 11.0 * degv[v] + 0.1 * rad[v];\n            }\n        } else if (mode == 2) {\n            // central low beauty support first\n            for (int v = 0; v < N; v++) {\n                key[v] = 8.0 * A[v] - 8.0 * degv[v] + 0.8 * rad[v];\n            }\n        } else if (mode == 3) {\n            // stronger centrality\n            for (int v = 0; v < N; v++) {\n                key[v] = 7.0 * A[v] - 10.0 * degv[v] + 1.5 * rad[v];\n            }\n        } else {\n            // randomized projection-based order\n            double theta = uniform_real_distribution<double>(0.0, 2.0 * acos(-1.0))(rng);\n            double c = cos(theta), s = sin(theta);\n            double wa = uniform_real_distribution<double>(5.0, 12.0)(rng);\n            double wd = uniform_real_distribution<double>(6.0, 14.0)(rng);\n            double wr = uniform_real_distribution<double>(0.0, 1.8)(rng);\n            double wp = uniform_real_distribution<double>(-0.7, 0.7)(rng);\n            for (int v = 0; v < N; v++) {\n                double proj = c * X[v] + s * Y[v];\n                key[v] = wa * A[v] - wd * degv[v] + wr * rad[v] + wp * proj + 1e-7 * v;\n            }\n        }\n        return make_perm_by_key(key);\n    }\n\n    // ---------- Permutation local search ----------\n    long long score_of_perm_cached(const vector<int>& perm) {\n        return eval_perm(perm, nullptr);\n    }\n\n    void random_insert_move(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        if (i < j) {\n            rotate(p.begin() + i, p.begin() + i + 1, p.begin() + j + 1);\n        } else {\n            rotate(p.begin() + j, p.begin() + i, p.begin() + i + 1);\n        }\n    }\n\n    void local_search_perm(vector<int>& perm, long long& best_score, double end_time) {\n        vector<int> cur = perm;\n        long long cur_score = best_score;\n\n        vector<int> best = perm;\n        long long best_local = best_score;\n\n        const double T0 = 1200.0;\n        const double T1 = 5.0;\n\n        while (elapsed() < end_time) {\n            double prog = min(1.0, elapsed() / end_time);\n            double temp = T0 * pow(T1 / T0, prog);\n\n            vector<int> cand = cur;\n            int type = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (type < 60) {\n                // insertion\n                int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                int v = cand[i];\n                int j;\n                if (A[v] >= 70 && i + 1 < N && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(i + 1, N - 1)(rng);\n                } else if (A[v] <= 30 && i > 0 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(0, i - 1)(rng);\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                }\n                random_insert_move(cand, i, j);\n            } else if (type < 90) {\n                // swap\n                int i = uniform_int_distribution<int>(0, N - 2)(rng);\n                int j;\n                if (uniform_int_distribution<int>(0, 99)(rng) < 75) {\n                    j = i + 1;\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (j == i) j = (j + 1) % N;\n                }\n                swap(cand[i], cand[j]);\n            } else {\n                // small block move\n                int l = uniform_int_distribution<int>(0, N - 1)(rng);\n                int r = uniform_int_distribution<int>(0, N - 1)(rng);\n                if (l > r) swap(l, r);\n                if (r - l >= 2) {\n                    int mid = uniform_int_distribution<int>(l + 1, r)(rng);\n                    rotate(cand.begin() + l, cand.begin() + mid, cand.begin() + r + 1);\n                }\n            }\n\n            long long sc = score_of_perm_cached(cand);\n            long long diff = sc - cur_score;\n\n            bool accept = false;\n            if (diff >= 0) {\n                accept = true;\n            } else {\n                double prob = exp((double)diff / temp);\n                double rr = uniform_real_distribution<double>(0.0, 1.0)(rng);\n                if (rr < prob) accept = true;\n            }\n\n            if (accept) {\n                cur.swap(cand);\n                cur_score = sc;\n                if (sc > best_local) {\n                    best_local = sc;\n                    best = cur;\n                }\n            }\n        }\n\n        // polish by greedy adjacent swaps\n        bool improved = true;\n        while (improved && elapsed() < end_time) {\n            improved = false;\n            for (int i = 0; i + 1 < N && elapsed() < end_time; i++) {\n                swap(best[i], best[i + 1]);\n                long long sc = score_of_perm_cached(best);\n                if (sc >= best_local) {\n                    if (sc > best_local) improved = true;\n                    best_local = sc;\n                } else {\n                    swap(best[i], best[i + 1]);\n                }\n            }\n        }\n\n        perm = move(best);\n        best_score = best_local;\n    }\n\n    // ---------- Tree improvement ----------\n    struct Info {\n        vector<int> depth, tin, tout, subH;\n        vector<long long> subA;\n        long long score = 0;\n    };\n\n    Info build_info(const vector<int>& parent) {\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) {\n            if (parent[v] != -1) ch[parent[v]].push_back(v);\n        }\n\n        Info info;\n        info.depth.assign(N, 0);\n        info.tin.assign(N, 0);\n        info.tout.assign(N, 0);\n        info.subH.assign(N, 0);\n        info.subA.assign(N, 0);\n        info.score = 0;\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v) -> void {\n            info.tin[v] = timer++;\n            info.subA[v] = A[v];\n            info.subH[v] = 0;\n            info.score += 1LL * (info.depth[v] + 1) * A[v];\n            for (int c : ch[v]) {\n                info.depth[c] = info.depth[v] + 1;\n                self(self, c);\n                info.subA[v] += info.subA[c];\n                info.subH[v] = max(info.subH[v], info.subH[c] + 1);\n            }\n            info.tout[v] = timer;\n        };\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                info.depth[v] = 0;\n                dfs(dfs, v);\n            }\n        }\n        return info;\n    }\n\n    static bool is_ancestor(const Info& info, int a, int b) {\n        return info.tin[a] <= info.tin[b] && info.tout[b] <= info.tout[a];\n    }\n\n    long long improve_tree(vector<int>& parent, double end_time) {\n        long long last_score = -1;\n\n        while (elapsed() < end_time) {\n            Info info = build_info(parent);\n            last_score = info.score;\n\n            long long best_gain = 0;\n            int best_u = -1, best_v = -1;\n            int best_nd = -1;\n            long long best_sub = -1;\n\n            auto eval_move = [&](int u, int v) {\n                // move subtree rooted at v under u\n                if (parent[v] == u) return;\n                if (is_ancestor(info, v, u)) return;\n                if (info.depth[u] >= H) return;\n\n                int nd = info.depth[u] + 1;\n                if (nd <= info.depth[v]) return;\n                if (nd + info.subH[v] > H) return;\n\n                long long gain = 1LL * (nd - info.depth[v]) * info.subA[v];\n                if (gain > best_gain ||\n                    (gain == best_gain && nd > best_nd) ||\n                    (gain == best_gain && nd == best_nd && info.subA[v] > best_sub)) {\n                    best_gain = gain;\n                    best_u = u;\n                    best_v = v;\n                    best_nd = nd;\n                    best_sub = info.subA[v];\n                }\n            };\n\n            for (auto [a, b] : edges) {\n                eval_move(a, b);\n                eval_move(b, a);\n            }\n\n            if (best_gain <= 0) break;\n            parent[best_v] = best_u;\n        }\n\n        if (last_score == -1) last_score = build_info(parent).score;\n        return last_score;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            edges[i] = {u, v};\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        X.resize(N);\n        Y.resize(N);\n        for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n        st = chrono::steady_clock::now();\n\n        degv.assign(N, 0);\n        rad.assign(N, 0.0);\n        for (int v = 0; v < N; v++) {\n            degv[v] = (int)g[v].size();\n            double dx = X[v] - 500.0;\n            double dy = Y[v] - 500.0;\n            rad[v] = sqrt(dx * dx + dy * dy);\n        }\n\n        // 1) Generate multiple initial permutations\n        vector<pair<long long, vector<int>>> cand;\n        for (int mode = 0; mode <= 3; mode++) {\n            auto p = make_initial_perm(mode);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n        while ((int)cand.size() < 14 && elapsed() < 0.20) {\n            auto p = make_initial_perm(4);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n\n        sort(cand.begin(), cand.end(), [&](auto& a, auto& b) {\n            return a.first > b.first;\n        });\n\n        // 2) Optimize top few permutations\n        long long best_perm_score = -1;\n        vector<int> best_perm;\n        int K = min<int>(3, cand.size());\n\n        double perm_search_end = 1.45;\n        for (int i = 0; i < K && elapsed() < perm_search_end; i++) {\n            vector<int> p = cand[i].second;\n            long long sc = cand[i].first;\n\n            double remaining = perm_search_end - elapsed();\n            double slice_end = elapsed() + remaining / (K - i);\n            local_search_perm(p, sc, slice_end);\n\n            if (sc > best_perm_score) {\n                best_perm_score = sc;\n                best_perm = move(p);\n            }\n        }\n\n        if (best_perm.empty()) {\n            best_perm = cand[0].second;\n            best_perm_score = cand[0].first;\n        }\n\n        // 3) Build parent from best permutation\n        vector<int> best_parent;\n        long long base_score = eval_perm(best_perm, &best_parent);\n        long long best_score = base_score;\n\n        // 4) Final tree-based monotone improvement\n        long long improved_score = improve_tree(best_parent, TL);\n        if (improved_score > best_score) best_score = improved_score;\n\n        // Output\n        for (int v = 0; v < N; v++) {\n            if (v) cout << ' ';\n            cout << best_parent[v];\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int INF = 1e9;\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ULL;\n    XorShift(uint64_t seed = 0) {\n        x ^= seed + 0x9e3779b97f4a7c15ULL;\n        next();\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n = 0) : n(n), p(n), sz(n, 1) {\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\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 Analysis {\n    int N = 0, P = 0, F = 0;\n    vector<pair<int,int>> oni;\n    vector<int> firstRowFuku, lastRowFuku;\n    vector<int> firstColFuku, lastColFuku;\n    vector<vector<int>> reqDepth;\n    vector<vector<int>> opts;\n    vector<int> minDepth;\n    bool allSafe = true;\n    int guaranteedTail = INF; // sum of cheapest individual round-trip costs\n    int greedyTail = INF;     // cheap grouped upper bound\n};\n\nstruct MacroAction {\n    char dir;\n    int idx;\n    int k;\n    int removed;\n};\n\nstruct Cand {\n    uint64_t mask;\n    int cost;     // 2 * depth\n    int facility; // 0..79\n    int depth;    // 0..20\n};\n\nstruct SolveResult {\n    vector<int> depth; // size F\n    int cost = INF;\n};\n\nstruct MemoVal {\n    int cost = INF;\n    array<uint8_t, 80> depth{};\n};\n\nstatic inline int popcount64(uint64_t x) {\n    return __builtin_popcountll(x);\n}\n\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\nstatic uint64_t zob[20][20][3];\nstatic bool zob_inited = false;\n\nstatic void init_zob() {\n    if (zob_inited) return;\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < 20; i++) {\n        for (int j = 0; j < 20; j++) {\n            for (int t = 0; t < 3; t++) {\n                seed = splitmix64(seed + 0x9e3779b97f4a7c15ULL);\n                zob[i][j][t] = seed;\n            }\n        }\n    }\n    zob_inited = true;\n}\n\nstatic uint64_t hash_board(const vector<string>& B) {\n    uint64_t h = 0;\n    for (int i = 0; i < (int)B.size(); i++) {\n        for (int j = 0; j < (int)B[i].size(); j++) {\n            int t = 0;\n            if (B[i][j] == 'x') t = 1;\n            else if (B[i][j] == 'o') t = 2;\n            h ^= zob[i][j][t];\n        }\n    }\n    return h;\n}\n\nstatic int greedy_assign_upper_bound(const Analysis& A) {\n    int P = A.P, F = A.F;\n    if (P == 0) return 0;\n\n    vector<int> order(P);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if ((int)A.opts[a].size() != (int)A.opts[b].size())\n            return A.opts[a].size() < A.opts[b].size();\n        if (A.minDepth[a] != A.minDepth[b])\n            return A.minDepth[a] > A.minDepth[b];\n        return a < b;\n    });\n\n    vector<int> curMax(F, 0);\n    for (int p : order) {\n        int bestF = -1;\n        tuple<int,int,int,int> bestKey = {INF, INF, INF, INF};\n        for (int f : A.opts[p]) {\n            int d = A.reqDepth[p][f];\n            int inc = max(0, d - curMax[f]);\n            auto key = make_tuple(inc, d, curMax[f], f);\n            if (key < bestKey) {\n                bestKey = key;\n                bestF = f;\n            }\n        }\n        if (bestF == -1) return INF;\n        curMax[bestF] = max(curMax[bestF], A.reqDepth[p][bestF]);\n    }\n\n    int cost = 0;\n    for (int f = 0; f < F; f++) cost += 2 * curMax[f];\n    return cost;\n}\n\nstatic Analysis analyze_board(const vector<string>& B) {\n    int N = (int)B.size();\n    int F = 4 * N;\n\n    Analysis A;\n    A.N = N;\n    A.F = F;\n    A.firstRowFuku.assign(N, N);\n    A.lastRowFuku.assign(N, -1);\n    A.firstColFuku.assign(N, N);\n    A.lastColFuku.assign(N, -1);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (B[i][j] == 'o') {\n                A.firstRowFuku[i] = min(A.firstRowFuku[i], j);\n                A.lastRowFuku[i] = max(A.lastRowFuku[i], j);\n                A.firstColFuku[j] = min(A.firstColFuku[j], i);\n                A.lastColFuku[j] = max(A.lastColFuku[j], i);\n            } else if (B[i][j] == 'x') {\n                A.oni.push_back({i, j});\n            }\n        }\n    }\n\n    A.P = (int)A.oni.size();\n    A.reqDepth.assign(A.P, vector<int>(F, INF));\n    A.opts.assign(A.P, {});\n    A.minDepth.assign(A.P, INF);\n\n    auto idL = [&](int i) { return i; };\n    auto idR = [&](int i) { return N + i; };\n    auto idU = [&](int j) { return 2 * N + j; };\n    auto idD = [&](int j) { return 3 * N + j; };\n\n    A.allSafe = true;\n    A.guaranteedTail = 0;\n\n    for (int p = 0; p < A.P; p++) {\n        auto [i, j] = A.oni[p];\n\n        if (j < A.firstRowFuku[i]) {\n            int f = idL(i);\n            int d = j + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (j > A.lastRowFuku[i]) {\n            int f = idR(i);\n            int d = N - j;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i < A.firstColFuku[j]) {\n            int f = idU(j);\n            int d = i + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i > A.lastColFuku[j]) {\n            int f = idD(j);\n            int d = N - i;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n\n        if (A.opts[p].empty()) {\n            A.allSafe = false;\n            A.guaranteedTail = INF;\n        } else {\n            A.guaranteedTail += 2 * A.minDepth[p];\n        }\n    }\n\n    A.greedyTail = A.allSafe ? greedy_assign_upper_bound(A) : INF;\n    return A;\n}\n\nstatic vector<MacroAction> generate_macro_actions(const vector<string>& B, const Analysis& A) {\n    int N = A.N;\n    vector<MacroAction> res;\n\n    for (int i = 0; i < N; i++) {\n        int limL = A.firstRowFuku[i];\n        if (limL > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limL; k++) {\n                if (B[i][k - 1] == 'x') acc++;\n                if (acc > 0) res.push_back({'L', i, k, acc});\n            }\n        }\n        int limR = (A.lastRowFuku[i] == -1 ? N : N - 1 - A.lastRowFuku[i]);\n        if (limR > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limR; k++) {\n                if (B[i][N - k] == 'x') acc++;\n                if (acc > 0) res.push_back({'R', i, k, acc});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        int limU = A.firstColFuku[j];\n        if (limU > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limU; k++) {\n                if (B[k - 1][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'U', j, k, acc});\n            }\n        }\n        int limD = (A.lastColFuku[j] == -1 ? N : N - 1 - A.lastColFuku[j]);\n        if (limD > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limD; k++) {\n                if (B[N - k][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'D', j, k, acc});\n            }\n        }\n    }\n\n    return res;\n}\n\nstatic vector<string> apply_macro(const vector<string>& B, char dir, int idx, int k) {\n    int N = (int)B.size();\n    vector<string> C = B;\n\n    if (dir == 'L') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j] = B[idx][j + k];\n        C[idx] = t;\n    } else if (dir == 'R') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j + k] = B[idx][j];\n        C[idx] = t;\n    } else if (dir == 'U') {\n        for (int i = 0; i + k < N; i++) C[i][idx] = B[i + k][idx];\n        for (int i = N - k; i < N; i++) C[i][idx] = '.';\n    } else { // D\n        for (int i = 0; i + k < N; i++) C[i + k][idx] = B[i][idx];\n        for (int i = 0; i < k; i++) C[i][idx] = '.';\n    }\n    return C;\n}\n\nstatic vector<Cand> reduce_candidates(vector<Cand> v) {\n    if (v.empty()) return v;\n\n    sort(v.begin(), v.end(), [](const Cand& a, const Cand& b) {\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> dedup;\n    for (int i = 0; i < (int)v.size();) {\n        int j = i + 1;\n        Cand best = v[i];\n        while (j < (int)v.size() && v[j].mask == v[i].mask) {\n            if (v[j].cost < best.cost) best = v[j];\n            j++;\n        }\n        if (best.mask) dedup.push_back(best);\n        i = j;\n    }\n\n    sort(dedup.begin(), dedup.end(), [](const Cand& a, const Cand& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        int pa = popcount64(a.mask), pb = popcount64(b.mask);\n        if (pa != pb) return pa > pb;\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> res;\n    for (const auto& c : dedup) {\n        bool dominated = false;\n        for (const auto& d : res) {\n            if (d.cost <= c.cost && (c.mask & ~d.mask) == 0ULL) {\n                dominated = true;\n                break;\n            }\n        }\n        if (!dominated) res.push_back(c);\n    }\n    return res;\n}\n\nstruct FacilityOption {\n    uint64_t mask;\n    int cost;\n    int depth;\n};\n\nstatic SolveResult canonicalize_and_descent(\n    int m, int F,\n    const vector<Cand>& cands,\n    const vector<int>& selectedIds\n) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> curPos(F, 0);\n    for (int id : selectedIds) {\n        int f = cands[id].facility;\n        int d = cands[id].depth;\n        for (int p = 0; p < (int)opts[f].size(); p++) {\n            if (opts[f][p].depth == d) {\n                curPos[f] = max(curPos[f], p);\n                break;\n            }\n        }\n    }\n\n    vector<int> coverCnt(m, 0);\n    auto addMask = [&](uint64_t mask, int delta) {\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverCnt[b] += delta;\n            mask &= mask - 1;\n        }\n    };\n\n    for (int f = 0; f < F; f++) addMask(opts[f][curPos[f]].mask, +1);\n\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int f = 0; f < F; f++) {\n            int oldPos = curPos[f];\n            if (oldPos == 0) continue;\n\n            addMask(opts[f][oldPos].mask, -1);\n\n            int bestPos = oldPos;\n            for (int p = 0; p <= oldPos; p++) {\n                uint64_t mask = opts[f][p].mask;\n                bool ok = true;\n                for (int i = 0; i < m; i++) {\n                    int c = coverCnt[i] + ((mask >> i) & 1ULL);\n                    if (c == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (ok) {\n                    bestPos = p;\n                    break;\n                }\n            }\n\n            curPos[f] = bestPos;\n            addMask(opts[f][curPos[f]].mask, +1);\n            if (curPos[f] != oldPos) improved = true;\n        }\n    }\n\n    vector<int> depthByFacility(F, 0);\n    int totalCost = 0;\n    for (int f = 0; f < F; f++) {\n        depthByFacility[f] = opts[f][curPos[f]].depth;\n        totalCost += opts[f][curPos[f]].cost;\n    }\n    return {depthByFacility, totalCost};\n}\n\nstatic SolveResult greedy_component_heuristic(\n    int m, int F,\n    const vector<Cand>& cands\n) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> curPos(F, 0);\n    uint64_t fullMask = (m == 64 ? ~0ULL : ((1ULL << m) - 1ULL));\n    uint64_t covered = 0;\n\n    while (covered != fullMask) {\n        int bestF = -1, bestP = -1;\n        int bestInc = INF, bestGain = -1, bestFinalCost = INF;\n\n        for (int f = 0; f < F; f++) {\n            for (int p = curPos[f] + 1; p < (int)opts[f].size(); p++) {\n                uint64_t newbits = opts[f][p].mask & ~covered;\n                int gain = popcount64(newbits);\n                if (gain == 0) continue;\n                int inc = opts[f][p].cost - opts[f][curPos[f]].cost;\n\n                if (bestF == -1 ||\n                    1LL * inc * bestGain < 1LL * bestInc * gain ||\n                    (1LL * inc * bestGain == 1LL * bestInc * gain &&\n                     (gain > bestGain ||\n                      (gain == bestGain && opts[f][p].cost < bestFinalCost)))) {\n                    bestF = f;\n                    bestP = p;\n                    bestInc = inc;\n                    bestGain = gain;\n                    bestFinalCost = opts[f][p].cost;\n                }\n            }\n        }\n\n        if (bestF == -1) break;\n        curPos[bestF] = bestP;\n        covered |= opts[bestF][bestP].mask;\n    }\n\n    vector<int> selectedIds;\n    for (int f = 0; f < F; f++) {\n        if (curPos[f] == 0) continue;\n        int depth = opts[f][curPos[f]].depth;\n        for (int id = 0; id < (int)cands.size(); id++) {\n            if (cands[id].facility == f && cands[id].depth == depth) {\n                selectedIds.push_back(id);\n                break;\n            }\n        }\n    }\n\n    return canonicalize_and_descent(m, F, cands, selectedIds);\n}\n\nstatic SolveResult exact_small_component(\n    int m, int F,\n    const vector<Cand>& cands\n) {\n    vector<vector<int>> coverByPoint(m);\n    for (int id = 0; id < (int)cands.size(); id++) {\n        uint64_t mask = cands[id].mask;\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverByPoint[b].push_back(id);\n            mask &= mask - 1;\n        }\n    }\n\n    for (int i = 0; i < m; i++) {\n        sort(coverByPoint[i].begin(), coverByPoint[i].end(), [&](int a, int b) {\n            int pa = popcount64(cands[a].mask), pb = popcount64(cands[b].mask);\n            if (pa != pb) return pa > pb;\n            if (cands[a].cost != cands[b].cost) return cands[a].cost < cands[b].cost;\n            return a < b;\n        });\n    }\n\n    uint32_t FULL = (m == 32 ? 0xFFFFFFFFu : ((1u << m) - 1u));\n    const uint16_t UNK = 65535;\n\n    vector<uint16_t> memo((size_t)FULL + 1, UNK);\n    vector<uint16_t> choice((size_t)FULL + 1, UNK);\n\n    function<uint16_t(uint32_t)> dfs = [&](uint32_t mask) -> uint16_t {\n        if (mask == 0) return 0;\n        uint16_t &ret = memo[mask];\n        if (ret != UNK) return ret;\n\n        int pivot = -1;\n        int bestCnt = INF;\n        uint32_t tmp = mask;\n        while (tmp) {\n            int b = __builtin_ctz(tmp);\n            int cnt = (int)coverByPoint[b].size();\n            if (cnt < bestCnt) {\n                bestCnt = cnt;\n                pivot = b;\n            }\n            tmp &= tmp - 1;\n        }\n\n        uint16_t best = UNK, bestId = UNK;\n        for (int id : coverByPoint[pivot]) {\n            uint32_t nmask = mask & ~(uint32_t)cands[id].mask;\n            uint16_t sub = dfs(nmask);\n            uint16_t val = (uint16_t)(cands[id].cost + sub);\n            if (best == UNK || val < best) {\n                best = val;\n                bestId = (uint16_t)id;\n            }\n        }\n        ret = best;\n        choice[mask] = bestId;\n        return ret;\n    };\n\n    (void)dfs(FULL);\n\n    vector<int> selectedIds;\n    uint32_t mask = FULL;\n    while (mask) {\n        int id = choice[mask];\n        selectedIds.push_back(id);\n        mask &= ~(uint32_t)cands[id].mask;\n    }\n\n    return canonicalize_and_descent(m, F, cands, selectedIds);\n}\n\nstatic SolveResult solve_setcover_tail(const Analysis& A) {\n    int P = A.P, F = A.F;\n    SolveResult ret;\n    ret.depth.assign(F, 0);\n    if (!A.allSafe) {\n        ret.cost = INF;\n        return ret;\n    }\n    if (P == 0) {\n        ret.cost = 0;\n        return ret;\n    }\n\n    vector<Cand> gcands;\n    for (int f = 0; f < F; f++) {\n        vector<pair<int,int>> v;\n        for (int p = 0; p < P; p++) if (A.reqDepth[p][f] < INF) v.push_back({A.reqDepth[p][f], p});\n        sort(v.begin(), v.end());\n\n        uint64_t mask = 0;\n        for (int i = 0; i < (int)v.size();) {\n            int d = v[i].first;\n            while (i < (int)v.size() && v[i].first == d) {\n                mask |= (1ULL << v[i].second);\n                i++;\n            }\n            gcands.push_back({mask, 2 * d, f, d});\n        }\n    }\n\n    gcands = reduce_candidates(gcands);\n\n    DSU dsu(P);\n    for (const auto& c : gcands) {\n        if (popcount64(c.mask) <= 1) continue;\n        int first = __builtin_ctzll(c.mask);\n        uint64_t tmp = c.mask & (c.mask - 1);\n        while (tmp) {\n            int b = __builtin_ctzll(tmp);\n            dsu.unite(first, b);\n            tmp &= tmp - 1;\n        }\n    }\n\n    unordered_map<int, vector<int>> groups;\n    for (int p = 0; p < P; p++) groups[dsu.find(p)].push_back(p);\n\n    vector<int> finalDepth(F, 0);\n    int finalCost = 0;\n\n    for (auto& [root, pts] : groups) {\n        int m = (int)pts.size();\n        vector<int> g2l(P, -1);\n        for (int i = 0; i < m; i++) g2l[pts[i]] = i;\n\n        uint64_t compGlobalMask = 0;\n        for (int p : pts) compGlobalMask |= (1ULL << p);\n\n        vector<Cand> lcands;\n        for (const auto& c : gcands) {\n            uint64_t inter = c.mask & compGlobalMask;\n            if (!inter) continue;\n            if ((c.mask & ~compGlobalMask) != 0ULL) continue;\n\n            uint64_t lmask = 0;\n            uint64_t tmp = c.mask;\n            while (tmp) {\n                int gp = __builtin_ctzll(tmp);\n                lmask |= (1ULL << g2l[gp]);\n                tmp &= tmp - 1;\n            }\n            lcands.push_back({lmask, c.cost, c.facility, c.depth});\n        }\n\n        lcands = reduce_candidates(lcands);\n\n        SolveResult comp;\n        if (m <= 22) comp = exact_small_component(m, F, lcands);\n        else comp = greedy_component_heuristic(m, F, lcands);\n\n        for (int f = 0; f < F; f++) finalDepth[f] = max(finalDepth[f], comp.depth[f]);\n        finalCost += comp.cost;\n    }\n\n    ret.depth = std::move(finalDepth);\n    ret.cost = finalCost;\n    return ret;\n}\n\nstatic vector<int> build_individual_fallback_depth(const Analysis& A) {\n    vector<int> depth(A.F, 0);\n    for (int p = 0; p < A.P; p++) {\n        int bestF = -1, bestD = INF;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] < bestD) {\n                bestD = A.reqDepth[p][f];\n                bestF = f;\n            }\n        }\n        if (bestF != -1) depth[bestF] = max(depth[bestF], bestD);\n    }\n    return depth;\n}\n\nstatic int depth_cost(const vector<int>& depthByFacility) {\n    int s = 0;\n    for (int d : depthByFacility) s += 2 * d;\n    return s;\n}\n\nstatic vector<pair<char,int>> depth_to_ops(const vector<int>& depthByFacility, int N) {\n    vector<pair<char,int>> ans;\n    for (int f = 0; f < (int)depthByFacility.size(); f++) {\n        int k = depthByFacility[f];\n        if (k == 0) continue;\n\n        if (f < N) {\n            int i = f;\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n        } else if (f < 2 * N) {\n            int i = f - N;\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n        } else if (f < 3 * N) {\n            int j = f - 2 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n        } else {\n            int j = f - 3 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n        }\n    }\n    return ans;\n}\n\nstatic bool validate_depth_solution(const Analysis& A, const vector<int>& depthByFacility) {\n    if (!A.allSafe) return false;\n    for (int p = 0; p < A.P; p++) {\n        bool ok = false;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] <= depthByFacility[f]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nstatic MemoVal solve_tail_memoized(\n    const vector<string>& board,\n    unordered_map<uint64_t, MemoVal>& memo\n) {\n    uint64_t h = hash_board(board);\n    auto it = memo.find(h);\n    if (it != memo.end()) return it->second;\n\n    Analysis A = analyze_board(board);\n    MemoVal mv;\n\n    if (!A.allSafe) {\n        mv.cost = INF;\n        memo[h] = mv;\n        return mv;\n    }\n\n    SolveResult res = solve_setcover_tail(A);\n    if (!validate_depth_solution(A, res.depth)) {\n        res.depth = build_individual_fallback_depth(A);\n        res.cost = depth_cost(res.depth);\n    }\n\n    mv.cost = res.cost;\n    for (int f = 0; f < 80; f++) mv.depth[f] = (uint8_t)res.depth[f];\n    memo[h] = mv;\n    return mv;\n}\n\nstruct CandidateState {\n    MacroAction act;\n    vector<string> board;\n    int quickTotal = INF;\n    int guaranteedTotal = INF;\n    uint64_t randKey = 0;\n};\n\nstruct StrongState {\n    MacroAction act;\n    vector<string> board;\n    MemoVal tail;\n    int total = INF;\n    int quickTotal = INF;\n    uint64_t randKey = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_zob();\n\n    int N;\n    cin >> N;\n    vector<string> originalBoard(N);\n    for (int i = 0; i < N; i++) cin >> originalBoard[i];\n\n    auto start = chrono::steady_clock::now();\n    auto searchDeadline = start + chrono::milliseconds(1750);\n\n    uint64_t seed = 0;\n    for (auto &row : originalBoard) for (char ch : row) seed = seed * 131 + ch;\n    XorShift rng(seed ^ 0x123456789abcdefULL);\n\n    unordered_map<uint64_t, MemoVal> tailMemo;\n    tailMemo.reserve(4096);\n\n    // Baseline: pure static tail from original board.\n    MemoVal baseTail = solve_tail_memoized(originalBoard, tailMemo);\n\n    vector<pair<char,int>> bestPrefixOps;\n    MemoVal bestTail = baseTail;\n    int bestTotal = baseTail.cost;\n\n    // Multiple randomized hill-climbing restarts.\n    int restart = 0;\n    while (chrono::steady_clock::now() < searchDeadline) {\n        vector<string> board = originalBoard;\n        vector<pair<char,int>> prefixOps;\n        MemoVal curTail = baseTail;\n        int curTotal = curTail.cost;\n\n        while (chrono::steady_clock::now() < searchDeadline) {\n            Analysis A = analyze_board(board);\n            if (A.P == 0) {\n                curTail.cost = 0;\n                curTotal = (int)prefixOps.size();\n                break;\n            }\n            if (!A.allSafe) break;\n\n            auto acts = generate_macro_actions(board, A);\n            if (acts.empty()) break;\n\n            vector<CandidateState> candStates;\n            candStates.reserve(acts.size());\n\n            for (const auto& act : acts) {\n                if (chrono::steady_clock::now() >= searchDeadline) break;\n                if ((int)prefixOps.size() + act.k > 4 * N * N) continue;\n\n                auto nb = apply_macro(board, act.dir, act.idx, act.k);\n                Analysis na = analyze_board(nb);\n\n                if (!na.allSafe) continue;\n                if ((int)prefixOps.size() + act.k + na.guaranteedTail > 4 * N * N) continue;\n\n                CandidateState cs;\n                cs.act = act;\n                cs.board = std::move(nb);\n                cs.quickTotal = (int)prefixOps.size() + act.k + na.greedyTail;\n                cs.guaranteedTotal = (int)prefixOps.size() + act.k + na.guaranteedTail;\n                cs.randKey = rng.next();\n\n                // allow a little slack in quick screening\n                if (cs.quickTotal <= curTotal + 8 || cs.guaranteedTotal < curTotal) {\n                    candStates.push_back(std::move(cs));\n                }\n            }\n\n            if (candStates.empty()) break;\n\n            sort(candStates.begin(), candStates.end(), [&](const CandidateState& a, const CandidateState& b) {\n                if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n                if (a.guaranteedTotal != b.guaranteedTotal) return a.guaranteedTotal < b.guaranteedTotal;\n                long long lhs = 1LL * a.act.removed * b.act.k;\n                long long rhs = 1LL * b.act.removed * a.act.k;\n                if (lhs != rhs) return lhs > rhs;\n                if (restart == 0) {\n                    if (a.act.removed != b.act.removed) return a.act.removed > b.act.removed;\n                    if (a.act.k != b.act.k) return a.act.k < b.act.k;\n                } else {\n                    if (a.randKey != b.randKey) return a.randKey < b.randKey;\n                }\n                if (a.act.dir != b.act.dir) return a.act.dir < b.act.dir;\n                return a.act.idx < b.act.idx;\n            });\n\n            int shortlist = (restart == 0 ? 6 : 8);\n            shortlist = min(shortlist, (int)candStates.size());\n\n            vector<StrongState> strongs;\n            strongs.reserve(shortlist);\n\n            for (int i = 0; i < shortlist; i++) {\n                if (chrono::steady_clock::now() >= searchDeadline) break;\n\n                StrongState ss;\n                ss.act = candStates[i].act;\n                ss.board = std::move(candStates[i].board);\n                ss.tail = solve_tail_memoized(ss.board, tailMemo);\n                ss.total = (int)prefixOps.size() + ss.act.k + ss.tail.cost;\n                ss.quickTotal = candStates[i].quickTotal;\n                ss.randKey = candStates[i].randKey;\n\n                if (ss.total <= 4 * N * N) strongs.push_back(std::move(ss));\n            }\n\n            if (strongs.empty()) break;\n\n            sort(strongs.begin(), strongs.end(), [&](const StrongState& a, const StrongState& b) {\n                if (a.total != b.total) return a.total < b.total;\n                if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n                long long lhs = 1LL * a.act.removed * b.act.k;\n                long long rhs = 1LL * b.act.removed * a.act.k;\n                if (lhs != rhs) return lhs > rhs;\n                if (restart == 0) {\n                    if (a.act.removed != b.act.removed) return a.act.removed > b.act.removed;\n                    if (a.act.k != b.act.k) return a.act.k < b.act.k;\n                } else {\n                    if (a.randKey != b.randKey) return a.randKey < b.randKey;\n                }\n                if (a.act.dir != b.act.dir) return a.act.dir < b.act.dir;\n                return a.act.idx < b.act.idx;\n            });\n\n            int bestStrong = strongs[0].total;\n            vector<int> choices;\n            for (int i = 0; i < (int)strongs.size(); i++) {\n                if (strongs[i].total == bestStrong) choices.push_back(i);\n            }\n\n            int pick = 0;\n            if (restart > 0 && !choices.empty()) {\n                pick = choices[rng.next_int(0, (int)choices.size() - 1)];\n            }\n\n            if (strongs[pick].total >= curTotal) break;\n\n            for (int t = 0; t < strongs[pick].act.k; t++) {\n                prefixOps.push_back({strongs[pick].act.dir, strongs[pick].act.idx});\n            }\n            board = std::move(strongs[pick].board);\n            curTail = strongs[pick].tail;\n            curTotal = strongs[pick].total;\n        }\n\n        if (curTotal < bestTotal) {\n            bestTotal = curTotal;\n            bestPrefixOps = std::move(prefixOps);\n            bestTail = curTail;\n        }\n\n        restart++;\n    }\n\n    vector<int> bestTailDepth(4 * N, 0);\n    for (int f = 0; f < 4 * N; f++) bestTailDepth[f] = bestTail.depth[f];\n    auto tailOps = depth_to_ops(bestTailDepth, N);\n\n    // Safety fallback if needed.\n    if ((int)bestPrefixOps.size() + (int)tailOps.size() > 4 * N * N) {\n        Analysis A = analyze_board(originalBoard);\n        vector<int> fb = build_individual_fallback_depth(A);\n        bestPrefixOps.clear();\n        tailOps = depth_to_ops(fb, N);\n    }\n\n    for (auto [c, p] : bestPrefixOps) cout << c << ' ' << p << '\\n';\n    for (auto [c, p] : tailOps) cout << c << ' ' << p << '\\n';\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\n#include <atcoder/scc>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic inline long long AbsLL(long long x) { return x >= 0 ? x : -x; }\n\nstruct State {\n    vector<int> a, b;\n    vector<int> cnt;\n    vector<int> useA, useB;\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstruct Solver {\n    int N, L;\n    vector<int> T;\n    vector<int> D; // incoming target: D[0]=T[0]-1, D[i]=T[i] for i>0\n    mt19937_64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver(int N_, int L_, vector<int> T_)\n        : N(N_), L(L_), T(std::move(T_)),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        st = chrono::steady_clock::now();\n        D = T;\n        D[0]--;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    State simulate(const vector<int>& a, const vector<int>& b) {\n        State res;\n        res.a = a;\n        res.b = b;\n        res.cnt.assign(N, 0);\n        res.useA.assign(N, 0);\n        res.useB.assign(N, 0);\n\n        int x = 0;\n        res.cnt[0] = 1;\n\n        for (int step = 1; step < L; step++) {\n            if (res.cnt[x] & 1) {\n                res.useA[x]++;\n                x = a[x];\n            } else {\n                res.useB[x]++;\n                x = b[x];\n            }\n            res.cnt[x]++;\n        }\n        res.last = x;\n\n        long long e = 0;\n        for (int i = 0; i < N; i++) e += AbsLL((long long)res.cnt[i] - T[i]);\n        res.err = e;\n        return res;\n    }\n\n    vector<vector<int>> get_sccs(const vector<int>& a, const vector<int>& b) {\n        scc_graph g(N);\n        for (int i = 0; i < N; i++) {\n            g.add_edge(i, a[i]);\n            g.add_edge(i, b[i]);\n        }\n        return g.scc();\n    }\n\n    void repair_components(vector<int>& a, vector<int>& b,\n                           const vector<int>& wA, const vector<int>& wB,\n                           vector<long long>& R) {\n        for (int iter = 0; iter < 4; iter++) {\n            auto comps = get_sccs(a, b);\n            if ((int)comps.size() <= 1) return;\n\n            int K = (int)comps.size();\n            vector<int> cid(N, -1);\n            for (int i = 0; i < K; i++) {\n                for (int v : comps[i]) cid[v] = i;\n            }\n\n            vector<int> rep(K);\n            for (int i = 0; i < K; i++) {\n                int best = comps[i][0];\n                for (int v : comps[i]) {\n                    if (T[v] < T[best]) best = v;\n                }\n                rep[i] = best;\n            }\n\n            for (int i = 0; i < K; i++) {\n                int target = rep[(i + 1) % K];\n\n                long long bestKey = (1LL << 62);\n                int bestu = -1, bestslot = -1, bestold = -1, bestw = 0;\n\n                for (int u : comps[i]) {\n                    for (int slot = 0; slot < 2; slot++) {\n                        int old = (slot == 0 ? a[u] : b[u]);\n                        int w = (slot == 0 ? wA[u] : wB[u]);\n\n                        if (old == target) {\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                            bestKey = LLONG_MIN;\n                            break;\n                        }\n\n                        long long delta =\n                            AbsLL(R[old] + w) + AbsLL(R[target] - w)\n                            - AbsLL(R[old]) - AbsLL(R[target]);\n\n                        long long key = delta * 1000000LL + w;\n                        int other = (slot == 0 ? b[u] : a[u]);\n                        if (cid[other] == i) key -= 1;\n\n                        if (key < bestKey) {\n                            bestKey = key;\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                        }\n                    }\n                    if (bestKey == LLONG_MIN) break;\n                }\n\n                if (bestu != -1 && bestold != target) {\n                    R[bestold] += bestw;\n                    R[target] -= bestw;\n                    if (bestslot == 0) a[bestu] = target;\n                    else b[bestu] = target;\n                }\n            }\n        }\n    }\n\n    State build_from_weights(const vector<int>& wA, const vector<int>& wB,\n                             const vector<int>* baseA = nullptr,\n                             const vector<int>* baseB = nullptr,\n                             int mode = 0) {\n        vector<long long> R(N);\n        for (int i = 0; i < N; i++) R[i] = D[i];\n\n        vector<int> W(2 * N), dest(2 * N, -1);\n        for (int i = 0; i < N; i++) {\n            W[2 * i] = wA[i];\n            W[2 * i + 1] = wB[i];\n        }\n\n        vector<int> ids(2 * N);\n        iota(ids.begin(), ids.end(), 0);\n        shuffle(ids.begin(), ids.end(), rng);\n        stable_sort(ids.begin(), ids.end(), [&](int p, int q) {\n            if (W[p] != W[q]) return W[p] > W[q];\n            return p < q;\n        });\n\n        long long same_pen = (mode % 4 == 0 ? 20 : mode % 4 == 1 ? 80 : mode % 4 == 2 ? 200 : 500);\n        long long self_pen = (mode % 5 == 0 ? 10 : mode % 5 == 1 ? 80 : mode % 5 == 2 ? 200 : mode % 5 == 3 ? 500 : 1200);\n        long long keep_bonus = baseA ? (mode % 3 == 0 ? 30 : mode % 3 == 1 ? 100 : 250) : 0;\n\n        vector<int> first_dest(N, -1);\n\n        for (int pid : ids) {\n            int owner = pid / 2;\n            int w = W[pid];\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(N);\n\n            for (int j = 0; j < N; j++) {\n                long long delta = AbsLL(R[j] - w) - AbsLL(R[j]);\n                long long sc = delta * 1000;\n                if (first_dest[owner] == j) sc += same_pen;\n                if (j == owner) sc += self_pen;\n                if (baseA != nullptr && baseB != nullptr) {\n                    int bd = (pid % 2 == 0 ? (*baseA)[owner] : (*baseB)[owner]);\n                    if (bd == j) sc -= keep_bonus;\n                }\n                sc += (long long)(rng() % 23);\n                cand.push_back({sc, j});\n            }\n\n            int pickK = min(6, N);\n            nth_element(cand.begin(), cand.begin() + (pickK - 1), cand.end());\n            sort(cand.begin(), cand.begin() + pickK);\n\n            int choose = (int)(rng() % pickK);\n            int j = cand[choose].second;\n            dest[pid] = j;\n            if (first_dest[owner] == -1) first_dest[owner] = j;\n            R[j] -= w;\n        }\n\n        for (int pass = 0; pass < 5; pass++) {\n            bool changed = false;\n            shuffle(ids.begin(), ids.end(), rng);\n\n            for (int pid : ids) {\n                int owner = pid / 2;\n                int w = W[pid];\n                int u = dest[pid];\n\n                long long bestDelta = 0;\n                int bestV = u;\n\n                for (int v = 0; v < N; v++) if (v != u) {\n                    long long delta =\n                        AbsLL(R[u] + w) + AbsLL(R[v] - w)\n                        - AbsLL(R[u]) - AbsLL(R[v]);\n\n                    int other = (pid % 2 == 0 ? dest[2 * owner + 1] : dest[2 * owner]);\n                    if (v == owner) delta += self_pen;\n                    if (v == other) delta += same_pen;\n                    if (u == owner) delta -= self_pen;\n                    if (u == other) delta -= same_pen;\n\n                    if (delta < bestDelta || (delta == bestDelta && ((rng() & 1ULL) != 0))) {\n                        bestDelta = delta;\n                        bestV = v;\n                    }\n                }\n\n                if (bestV != u && bestDelta < 0) {\n                    R[u] += w;\n                    R[bestV] -= w;\n                    dest[pid] = bestV;\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        for (int it = 0; it < 500; it++) {\n            int p = (int)(rng() % (2 * N));\n            int q = (int)(rng() % (2 * N));\n            if (p == q) continue;\n\n            int u = dest[p], v = dest[q];\n            if (u == v) continue;\n\n            int w1 = W[p], w2 = W[q];\n            long long delta =\n                AbsLL(R[u] + w1 - w2) + AbsLL(R[v] + w2 - w1)\n                - AbsLL(R[u]) - AbsLL(R[v]);\n\n            if (delta < 0 || (delta == 0 && (rng() & 7ULL) == 0)) {\n                R[u] += w1 - w2;\n                R[v] += w2 - w1;\n                swap(dest[p], dest[q]);\n            }\n        }\n\n        vector<int> a(N), b(N);\n        for (int i = 0; i < N; i++) {\n            a[i] = dest[2 * i];\n            b[i] = dest[2 * i + 1];\n        }\n\n        repair_components(a, b, wA, wB, R);\n        return simulate(a, b);\n    }\n\n    pair<vector<int>, vector<int>> initial_weights_assuming_last(int last) {\n        vector<int> wA(N), wB(N);\n        for (int i = 0; i < N; i++) {\n            wA[i] = (T[i] + 1) / 2;\n            wB[i] = T[i] / 2;\n        }\n        if (T[last] % 2 == 1) wA[last]--;\n        else wB[last]--;\n        return {wA, wB};\n    }\n\n    State build_initial(int last, int mode) {\n        auto wb = initial_weights_assuming_last(last);\n        return build_from_weights(wb.first, wb.second, nullptr, nullptr, mode);\n    }\n\n    State rebuild_from_state(const State& cur, int mode) {\n        return build_from_weights(cur.useA, cur.useB, &cur.a, &cur.b, mode);\n    }\n\n    State guided_local_improve(State cur, double time_limit) {\n        while (elapsed() < time_limit) {\n            vector<long long> diff(N);\n            for (int i = 0; i < N; i++) diff[i] = (long long)cur.cnt[i] - T[i];\n\n            vector<int> under;\n            for (int i = 0; i < N; i++) if (diff[i] < 0) under.push_back(i);\n            sort(under.begin(), under.end(), [&](int x, int y) {\n                return diff[x] < diff[y];\n            });\n\n            struct Cand {\n                long long approx;\n                int node, slot, to;\n            };\n            vector<Cand> cands;\n            cands.reserve(2000);\n\n            for (int i = 0; i < N; i++) {\n                for (int slot = 0; slot < 2; slot++) {\n                    int w = (slot == 0 ? cur.useA[i] : cur.useB[i]);\n                    if (w == 0) continue;\n                    int u = (slot == 0 ? cur.a[i] : cur.b[i]);\n\n                    int lim = min<int>(12, (int)under.size());\n                    for (int k = 0; k < lim; k++) {\n                        int v = under[k];\n                        if (v == u) continue;\n                        long long approx =\n                            AbsLL(diff[u] - w) + AbsLL(diff[v] + w)\n                            - AbsLL(diff[u]) - AbsLL(diff[v]);\n                        if (approx <= 0) {\n                            cands.push_back({approx, i, slot, v});\n                        }\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            shuffle(cands.begin(), cands.end(), rng);\n            stable_sort(cands.begin(), cands.end(), [&](const Cand& x, const Cand& y) {\n                return x.approx < y.approx;\n            });\n\n            int evals = min<int>(8, (int)cands.size());\n            State bestNext = cur;\n            bool improved = false;\n\n            for (int i = 0; i < evals && elapsed() < time_limit; i++) {\n                auto cd = cands[i];\n                vector<int> na = cur.a, nb = cur.b;\n                if (cd.slot == 0) {\n                    if (na[cd.node] == cd.to) continue;\n                    na[cd.node] = cd.to;\n                } else {\n                    if (nb[cd.node] == cd.to) continue;\n                    nb[cd.node] = cd.to;\n                }\n\n                State nxt = simulate(na, nb);\n                if (nxt.err < bestNext.err) {\n                    bestNext = std::move(nxt);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            cur = std::move(bestNext);\n        }\n        return cur;\n    }\n\n    State solve() {\n        State best;\n        best.err = (1LL << 60);\n\n        vector<int> pos;\n        for (int i = 0; i < N; i++) if (T[i] > 0) pos.push_back(i);\n        sort(pos.begin(), pos.end(), [&](int x, int y) {\n            if (T[x] != T[y]) return T[x] > T[y];\n            return x < y;\n        });\n\n        int mode = 0;\n        int tried = 0;\n\n        while (elapsed() < 0.60) {\n            int last;\n            if (tried < min<int>(10, (int)pos.size())) last = pos[tried];\n            else last = pos[(int)(rng() % pos.size())];\n\n            State cand = build_initial(last, mode++);\n            if (cand.err < best.err) best = std::move(cand);\n            tried++;\n        }\n\n        int no_improve = 0;\n        while (elapsed() < 1.75) {\n            State cand = rebuild_from_state(best, mode++);\n            cand = guided_local_improve(std::move(cand), 1.78);\n\n            if (cand.err < best.err) {\n                best = std::move(cand);\n                no_improve = 0;\n            } else {\n                no_improve++;\n            }\n\n            if (no_improve >= 3 && elapsed() < 1.75) {\n                State alt = rebuild_from_state(best, mode++);\n                if (alt.err < best.err) {\n                    best = std::move(alt);\n                    no_improve = 0;\n                }\n            }\n        }\n\n        best = guided_local_improve(std::move(best), 1.97);\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    vector<int> T(N);\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    Solver solver(N, L, T);\n    State ans = solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << ans.a[i] << ' ' << ans.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\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\nstruct Solver {\n    static constexpr double INF = 1e100;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<double> cx, cy;\n    vector<vector<double>> distm;\n    vector<uint32_t> morton_code;\n    int used_queries = 0;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffff;\n        x = (x ^ (x << 8)) & 0x00FF00FF;\n        x = (x ^ (x << 4)) & 0x0F0F0F0F;\n        x = (x ^ (x << 2)) & 0x33333333;\n        x = (x ^ (x << 1)) & 0x55555555;\n        return x;\n    }\n\n    static pair<int,int> norm_edge(int a, int b) {\n        if (a > b) swap(a, b);\n        return {a, b};\n    }\n\n    static uint64_t edge_key(int a, int b) {\n        if (a > b) swap(a, b);\n        return (uint64_t(uint32_t(a)) << 32) | uint32_t(b);\n    }\n\n    void input() {\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        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx.resize(N); cy.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n        }\n\n        distm.assign(N, vector<double>(N, 0.0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                double dx = cx[i] - cx[j];\n                double dy = cy[i] - cy[j];\n                double d = sqrt(dx * dx + dy * dy);\n                distm[i][j] = distm[j][i] = d;\n            }\n        }\n\n        morton_code.resize(N);\n        for (int i = 0; i < N; i++) {\n            int xi = int(round(cx[i]));\n            int yi = int(round(cy[i]));\n            xi = max(0, min(16383, xi));\n            yi = max(0, min(16383, yi));\n            morton_code[i] = part1by1((uint32_t)xi) | (part1by1((uint32_t)yi) << 1);\n        }\n    }\n\n    // ---------- basic geometry / order ----------\n\n    vector<int> all_cities() {\n        vector<int> v(N);\n        iota(v.begin(), v.end(), 0);\n        return v;\n    }\n\n    vector<int> order_by_morton() {\n        vector<int> ord = all_cities();\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_by_projection(double dx, double dy) {\n        vector<int> ord = all_cities();\n        double norm = sqrt(dx * dx + dy * dy);\n        dx /= norm; dy /= norm;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double ka = cx[a] * dx + cy[a] * dy;\n            double kb = cx[b] * dx + cy[b] * dy;\n            if (fabs(ka - kb) > 1e-9) return ka < kb;\n            double ta = -cx[a] * dy + cy[a] * dx;\n            double tb = -cx[b] * dy + cy[b] * dx;\n            if (fabs(ta - tb) > 1e-9) return ta < tb;\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_group_by_key(const vector<int>& group, int mode) {\n        vector<int> ord = group;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto key = [&](int v) -> pair<double,double> {\n                if (mode == 0) return {cx[v], cy[v]};\n                if (mode == 1) return {cy[v], cx[v]};\n                if (mode == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n                if (mode == 3) return {cx[v] - cy[v], cx[v] + cy[v]};\n                return {double(morton_code[v]), double(v)};\n            };\n            auto ka = key(a), kb = key(b);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n        return ord;\n    }\n\n    // ---------- MST approximate ----------\n\n    double mst_cost_of_list(const vector<int>& cities) {\n        int n = (int)cities.size();\n        if (n <= 1) return 0.0;\n        vector<double> md(n, INF);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n        double ret = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            ret += md[v];\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) md[i] = d;\n            }\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_small(const vector<int>& cities) {\n        int n = (int)cities.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<double> md(n, INF);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back(norm_edge(cities[v], cities[par[v]]));\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) {\n                    md[i] = d;\n                    par[i] = v;\n                }\n            }\n        }\n        return edges;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_full(const vector<int>& cities) {\n        return approx_mst_edges_small(cities);\n    }\n\n    vector<int> mst_preorder_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        auto edges = approx_mst_edges_full(group);\n        unordered_map<int, vector<int>> adj;\n        adj.reserve(n * 2);\n        for (auto [a, b] : edges) {\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        }\n\n        int root = group[0];\n        for (int v : group) {\n            if (cx[v] + cy[v] < cx[root] + cy[root]) root = v;\n        }\n\n        vector<int> ord;\n        ord.reserve(n);\n        unordered_set<int> vis;\n        vis.reserve(n * 2);\n\n        vector<pair<int,int>> st;\n        st.push_back({root, -1});\n        while (!st.empty()) {\n            auto [v, p] = st.back();\n            st.pop_back();\n            if (vis.count(v)) continue;\n            vis.insert(v);\n            ord.push_back(v);\n\n            auto &neis = adj[v];\n            sort(neis.begin(), neis.end(), [&](int a, int b) {\n                double da = distm[v][a], db = distm[v][b];\n                if (fabs(da - db) > 1e-9) return da > db; // stack push reverse-like\n                return a > b;\n            });\n            for (int to : neis) if (to != p && !vis.count(to)) {\n                st.push_back({to, v});\n            }\n        }\n        if ((int)ord.size() != n) return group;\n        return ord;\n    }\n\n    // ---------- order-partition candidate ----------\n\n    struct OrderEvaluator {\n        const vector<int>& ord;\n        const vector<vector<double>>& distm;\n        int N;\n        vector<vector<double>> cache;\n\n        OrderEvaluator(const vector<int>& ord_, const vector<vector<double>>& distm_)\n            : ord(ord_), distm(distm_), N((int)ord_.size()),\n              cache(N + 1, vector<double>(N + 1, -1.0)) {}\n\n        double seg_cost(int l, int len) {\n            if (len <= 1) return 0.0;\n            double &res = cache[l][len];\n            if (res >= -0.5) return res;\n\n            vector<double> md(len, 1e100);\n            vector<char> used(len, 0);\n            md[0] = 0.0;\n            double ret = 0.0;\n\n            for (int it = 0; it < len; it++) {\n                int v = -1;\n                for (int i = 0; i < len; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                ret += md[v];\n                int cv = ord[l + v];\n                for (int i = 0; i < len; i++) if (!used[i]) {\n                    double d = distm[cv][ord[l + i]];\n                    if (d < md[i]) md[i] = d;\n                }\n            }\n            res = ret;\n            return res;\n        }\n\n        double total_cost(const vector<int>& sizes) {\n            int pos = 0;\n            double ret = 0.0;\n            for (int s : sizes) {\n                ret += seg_cost(pos, s);\n                pos += s;\n            }\n            return ret;\n        }\n\n        vector<int> improve(vector<int> sizes, int passes = 4) {\n            int m = (int)sizes.size();\n            for (int pass = 0; pass < passes; pass++) {\n                bool any = false;\n                int pos = 0;\n                for (int i = 0; i + 1 < m; i++) {\n                    int a = sizes[i], b = sizes[i + 1];\n                    double oldc = seg_cost(pos, a) + seg_cost(pos + a, b);\n                    double newc = seg_cost(pos, b) + seg_cost(pos + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[i], sizes[i + 1]);\n                        any = true;\n                    }\n                    pos += sizes[i];\n                }\n                if (!any) break;\n            }\n            return sizes;\n        }\n    };\n\n    struct Candidate {\n        vector<vector<int>> groups_seq; // group sequence with size multiset = G\n        double score = INF;\n    };\n\n    Candidate candidate_from_order(const vector<int>& ord, const vector<int>& size_seq) {\n        OrderEvaluator eval(ord, distm);\n        auto sizes = eval.improve(size_seq, 5);\n        double sc = eval.total_cost(sizes);\n\n        vector<vector<int>> groups;\n        int pos = 0;\n        for (int s : sizes) {\n            vector<int> grp;\n            grp.reserve(s);\n            for (int i = 0; i < s; i++) grp.push_back(ord[pos + i]);\n            pos += s;\n            groups.push_back(move(grp));\n        }\n        return {groups, sc};\n    }\n\n    // ---------- kd-style recursive partition candidate ----------\n\n    vector<vector<int>> kd_partition_rec(vector<int> cities, vector<int> sizes, int mode, int depth) {\n        if ((int)sizes.size() == 1) {\n            return {cities};\n        }\n\n        int total = 0;\n        for (int x : sizes) total += x;\n\n        int pref = 0;\n        int split_k = 1;\n        int best_diff = total;\n        for (int k = 1; k < (int)sizes.size(); k++) {\n            pref += sizes[k - 1];\n            int diff = abs(total - 2 * pref);\n            if (diff < best_diff) {\n                best_diff = diff;\n                split_k = k;\n            }\n        }\n\n        int left_need = 0;\n        for (int i = 0; i < split_k; i++) left_need += sizes[i];\n\n        auto choose_mode_key = [&](int v, int chosen) -> pair<double,double> {\n            if (chosen == 0) return {cx[v], cy[v]};\n            if (chosen == 1) return {cy[v], cx[v]};\n            if (chosen == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n            return {cx[v] - cy[v], cx[v] + cy[v]};\n        };\n\n        int chosen = 0;\n        if (mode == 0) {\n            double minx = 1e18, maxx = -1e18, miny = 1e18, maxy = -1e18;\n            for (int v : cities) {\n                minx = min(minx, cx[v]);\n                maxx = max(maxx, cx[v]);\n                miny = min(miny, cy[v]);\n                maxy = max(maxy, cy[v]);\n            }\n            chosen = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        } else if (mode == 1) {\n            chosen = depth % 2;\n        } else {\n            double mina = 1e18, maxa = -1e18, minb = 1e18, maxb = -1e18;\n            for (int v : cities) {\n                double a = cx[v] + cy[v];\n                double b = cx[v] - cy[v];\n                mina = min(mina, a); maxa = max(maxa, a);\n                minb = min(minb, b); maxb = max(maxb, b);\n            }\n            chosen = ((maxa - mina) >= (maxb - minb)) ? 2 : 3;\n        }\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            auto ka = choose_mode_key(a, chosen);\n            auto kb = choose_mode_key(b, chosen);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n\n        vector<int> left_cities(cities.begin(), cities.begin() + left_need);\n        vector<int> right_cities(cities.begin() + left_need, cities.end());\n        vector<int> left_sizes(sizes.begin(), sizes.begin() + split_k);\n        vector<int> right_sizes(sizes.begin() + split_k, sizes.end());\n\n        auto gl = kd_partition_rec(left_cities, left_sizes, mode, depth + 1);\n        auto gr = kd_partition_rec(right_cities, right_sizes, mode, depth + 1);\n        gl.insert(gl.end(), gr.begin(), gr.end());\n        return gl;\n    }\n\n    Candidate candidate_from_kd(const vector<int>& size_seq, int mode) {\n        vector<int> cities = all_cities();\n        auto groups = kd_partition_rec(cities, size_seq, mode, 0);\n        double sc = 0.0;\n        for (auto &g : groups) sc += mst_cost_of_list(g);\n        return {groups, sc};\n    }\n\n    // ---------- assign candidate sequence to original group indices ----------\n\n    vector<vector<int>> assign_to_original_indices(const vector<vector<int>>& groups_seq) {\n        unordered_map<int, vector<int>> mp;\n        mp.reserve(M * 2);\n        for (int i = 0; i < M; i++) mp[G[i]].push_back(i);\n        for (auto &kv : mp) reverse(kv.second.begin(), kv.second.end());\n\n        vector<vector<int>> ret(M);\n        for (auto &grp : groups_seq) {\n            int s = (int)grp.size();\n            int idx = mp[s].back();\n            mp[s].pop_back();\n            ret[idx] = grp;\n        }\n        return ret;\n    }\n\n    // ---------- local swap optimization ----------\n\n    double sqdist_city_to_point(int v, double x, double y) {\n        double dx = cx[v] - x;\n        double dy = cy[v] - y;\n        return dx * dx + dy * dy;\n    }\n\n    void recompute_group_info(const vector<vector<int>>& groups, int gid,\n                              vector<double>& gcx, vector<double>& gcy, vector<double>& gcost) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[gid]) {\n            sx += cx[v];\n            sy += cy[v];\n        }\n        gcx[gid] = sx / groups[gid].size();\n        gcy[gid] = sy / groups[gid].size();\n        gcost[gid] = mst_cost_of_list(groups[gid]);\n    }\n\n    void local_swap_optimize(vector<vector<int>>& groups) {\n        vector<double> gcx(M), gcy(M), gcost(M);\n        for (int i = 0; i < M; i++) {\n            recompute_group_info(groups, i, gcx, gcy, gcost);\n        }\n\n        const int PASSES = 2;\n        const int K_NEI = 5;\n        const int K_CAND = 4;\n\n        for (int pass = 0; pass < PASSES; pass++) {\n            bool any = false;\n\n            vector<vector<int>> neigh(M);\n            for (int i = 0; i < M; i++) {\n                vector<pair<double,int>> ds;\n                ds.reserve(M - 1);\n                for (int j = 0; j < M; j++) if (i != j) {\n                    double dx = gcx[i] - gcx[j];\n                    double dy = gcy[i] - gcy[j];\n                    ds.push_back({dx * dx + dy * dy, j});\n                }\n                nth_element(ds.begin(), ds.begin() + min(K_NEI, (int)ds.size()), ds.end());\n                sort(ds.begin(), ds.begin() + min(K_NEI, (int)ds.size()));\n                for (int t = 0; t < min(K_NEI, (int)ds.size()); t++) neigh[i].push_back(ds[t].second);\n            }\n\n            set<pair<int,int>> pairs;\n            for (int i = 0; i < M; i++) {\n                for (int j : neigh[i]) {\n                    if (i < j) pairs.insert({i, j});\n                    else pairs.insert({j, i});\n                }\n            }\n\n            for (auto [a, b] : pairs) {\n                auto pick_candidates = [&](int from, int to) {\n                    vector<pair<double,int>> cand;\n                    cand.reserve(groups[from].size());\n                    for (int idx = 0; idx < (int)groups[from].size(); idx++) {\n                        int v = groups[from][idx];\n                        double score = sqdist_city_to_point(v, gcx[to], gcy[to]) - sqdist_city_to_point(v, gcx[from], gcy[from]);\n                        cand.push_back({score, idx});\n                    }\n                    int k = min(K_CAND, (int)cand.size());\n                    nth_element(cand.begin(), cand.begin() + k, cand.end());\n                    sort(cand.begin(), cand.begin() + k);\n                    vector<int> ret;\n                    for (int i = 0; i < k; i++) ret.push_back(cand[i].second);\n                    return ret;\n                };\n\n                auto ca = pick_candidates(a, b);\n                auto cb = pick_candidates(b, a);\n\n                double old_cost = gcost[a] + gcost[b];\n                double best_new = old_cost;\n                int besta = -1, bestb = -1;\n\n                for (int ia : ca) {\n                    for (int ib : cb) {\n                        vector<int> ga = groups[a];\n                        vector<int> gb = groups[b];\n                        swap(ga[ia], gb[ib]);\n                        double nc = mst_cost_of_list(ga) + mst_cost_of_list(gb);\n                        if (nc + 1e-9 < best_new) {\n                            best_new = nc;\n                            besta = ia;\n                            bestb = ib;\n                        }\n                    }\n                }\n\n                if (besta != -1) {\n                    swap(groups[a][besta], groups[b][bestb]);\n                    recompute_group_info(groups, a, gcx, gcy, gcost);\n                    recompute_group_info(groups, b, gcx, gcy, gcost);\n                    any = true;\n                }\n            }\n\n            if (!any) break;\n        }\n    }\n\n    // ---------- grouping main ----------\n\n    vector<vector<int>> build_groups() {\n        vector<Candidate> cands;\n\n        vector<int> ascG = G;\n        sort(ascG.begin(), ascG.end());\n        vector<int> descG = G;\n        sort(descG.rbegin(), descG.rend());\n\n        vector<vector<int>> size_seqs = {G, ascG, descG};\n\n        // order-based candidates\n        vector<vector<int>> orders;\n        orders.push_back(order_by_morton());\n        orders.push_back(order_by_projection(1, 0));\n        orders.push_back(order_by_projection(0, 1));\n        orders.push_back(order_by_projection(1, 1));\n        orders.push_back(order_by_projection(1, -1));\n        orders.push_back(order_by_projection(cos(M_PI / 8.0), sin(M_PI / 8.0)));\n        orders.push_back(order_by_projection(cos(3 * M_PI / 8.0), sin(3 * M_PI / 8.0)));\n\n        for (auto &ord : orders) {\n            for (auto &sz : size_seqs) {\n                cands.push_back(candidate_from_order(ord, sz));\n            }\n        }\n\n        // kd-based candidates\n        for (auto &sz : size_seqs) {\n            for (int mode = 0; mode < 3; mode++) {\n                cands.push_back(candidate_from_kd(sz, mode));\n            }\n        }\n\n        Candidate best;\n        best.score = INF;\n        for (auto &c : cands) {\n            if (c.score < best.score) best = c;\n        }\n\n        auto groups = assign_to_original_indices(best.groups_seq);\n        local_swap_optimize(groups);\n        return groups;\n    }\n\n    // ---------- route construction with overlapping windows ----------\n\n    vector<pair<int,int>> make_primary_windows_indices(int n) {\n        vector<pair<int,int>> res; // {start, len}\n        if (n < 2) return res;\n        int s = 0;\n        while (true) {\n            int len = min(L, n - s);\n            if (len < 2) break;\n            res.push_back({s, len});\n            if (s + len >= n) break;\n            s = s + len - 1; // overlap 1\n        }\n        return res;\n    }\n\n    vector<pair<int,int>> make_extra_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n <= L) return res;\n\n        auto primary = make_primary_windows_indices(n);\n        set<int> used_starts;\n        for (auto [s, len] : primary) used_starts.insert(s);\n\n        int max_start = n - L;\n        int shift = max(1, (L - 1) / 2);\n\n        for (int i = 0; i + 1 < (int)primary.size(); i++) {\n            int s1 = primary[i].first;\n            int s2 = primary[i + 1].first;\n            int cand = min(max_start, s1 + shift);\n            if (cand > s1 && cand < s2 && !used_starts.count(cand)) {\n                used_starts.insert(cand);\n                res.push_back({cand, L});\n            }\n            int cand2 = max(0, min(max_start, s2 - shift));\n            if (cand2 > s1 && cand2 < s2 && !used_starts.count(cand2)) {\n                used_starts.insert(cand2);\n                res.push_back({cand2, L});\n            }\n        }\n        return res;\n    }\n\n    double approx_union_tree_cost_for_order(const vector<int>& ord) {\n        int n = (int)ord.size();\n        if (n <= 1) return 0.0;\n        if (n <= L) return mst_cost_of_list(ord);\n\n        auto primary = make_primary_windows_indices(n);\n\n        unordered_set<uint64_t> eset;\n        eset.reserve(n * 8);\n\n        for (auto [s, len] : primary) {\n            vector<int> w(ord.begin() + s, ord.begin() + s + len);\n            auto e = approx_mst_edges_small(w);\n            for (auto [a, b] : e) eset.insert(edge_key(a, b));\n        }\n\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        unordered_set<int> vset(ord.begin(), ord.end());\n        DSU dsu(N);\n        double cost = 0.0;\n        int cnt = 0;\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) {\n                cost += e.first;\n                cnt++;\n                if (cnt == n - 1) break;\n            }\n        }\n        if (cnt != n - 1) {\n            // fallback shouldn't happen, but just in case\n            return mst_cost_of_list(ord);\n        }\n        return cost;\n    }\n\n    vector<int> choose_best_local_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        vector<vector<int>> cands;\n        cands.push_back(group);\n        cands.push_back(order_group_by_key(group, 4)); // morton\n        cands.push_back(order_group_by_key(group, 0)); // x\n        cands.push_back(order_group_by_key(group, 1)); // y\n        cands.push_back(order_group_by_key(group, 2)); // x+y\n        cands.push_back(order_group_by_key(group, 3)); // x-y\n        cands.push_back(mst_preorder_order(group));\n\n        double best_score = INF;\n        vector<int> best = group;\n        for (auto &ord : cands) {\n            double sc = approx_union_tree_cost_for_order(ord);\n            if (sc < best_score) {\n                best_score = sc;\n                best = ord;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> query(const vector<int>& cities) {\n        cout << \"? \" << cities.size();\n        for (int v : cities) cout << \" \" << v;\n        cout << endl;\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)cities.size() - 1);\n        for (int i = 0; i < (int)cities.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            ret.push_back(norm_edge(a, b));\n        }\n        used_queries++;\n        return ret;\n    }\n\n    struct GroupPlan {\n        vector<int> order;\n        vector<pair<int,int>> primary;\n        vector<pair<int,int>> extra_candidates;\n    };\n\n    struct ExtraQueryCand {\n        double priority;\n        int gid;\n        int start;\n        int len;\n        bool operator<(const ExtraQueryCand& other) const {\n            if (fabs(priority - other.priority) > 1e-9) return priority > other.priority;\n            if (gid != other.gid) return gid < other.gid;\n            return start < other.start;\n        }\n    };\n\n    vector<pair<int,int>> final_tree_from_edge_union(const vector<int>& group,\n                                                     const unordered_set<uint64_t>& eset) {\n        int n = (int)group.size();\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> ans;\n        ans.reserve(max(0, n - 1));\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) {\n                ans.push_back({a, b});\n                if ((int)ans.size() == n - 1) break;\n            }\n        }\n\n        // safety fallback\n        if ((int)ans.size() != n - 1) {\n            auto approx_all = approx_mst_edges_full(group);\n            ans = approx_all;\n        }\n        return ans;\n    }\n\n    void solve() {\n        input();\n\n        auto groups = build_groups();\n\n        vector<GroupPlan> plans(M);\n        int primary_queries = 0;\n\n        for (int i = 0; i < M; i++) {\n            plans[i].order = choose_best_local_order(groups[i]);\n            int n = (int)plans[i].order.size();\n            plans[i].primary = make_primary_windows_indices(n);\n            plans[i].extra_candidates = make_extra_windows_indices(n);\n            primary_queries += (int)plans[i].primary.size();\n        }\n\n        // primary_queries should be <= Q\n        int remain = max(0, Q - primary_queries);\n\n        vector<ExtraQueryCand> extra_all;\n        for (int i = 0; i < M; i++) {\n            for (auto [s, len] : plans[i].extra_candidates) {\n                vector<int> w(plans[i].order.begin() + s, plans[i].order.begin() + s + len);\n                double pr = mst_cost_of_list(w); // simple importance heuristic\n                extra_all.push_back({pr, i, s, len});\n            }\n        }\n        sort(extra_all.begin(), extra_all.end());\n\n        vector<vector<pair<int,int>>> chosen_extras(M);\n        for (int i = 0; i < min(remain, (int)extra_all.size()); i++) {\n            chosen_extras[extra_all[i].gid].push_back({extra_all[i].start, extra_all[i].len});\n        }\n\n        vector<unordered_set<uint64_t>> edge_unions(M);\n        for (int i = 0; i < M; i++) edge_unions[i].reserve(max(8, (int)groups[i].size() * 4));\n\n        // Query all primary windows\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        // Query selected extra windows\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : chosen_extras[gid]) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        // Build final trees\n        vector<vector<pair<int,int>>> answer_edges(M);\n        for (int gid = 0; gid < M; gid++) {\n            answer_edges[gid] = final_tree_from_edge_union(plans[gid].order, edge_unions[gid]);\n        }\n\n        cout << \"!\" << endl;\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (int i = 0; i < (int)ord.size(); i++) {\n                if (i) cout << ' ';\n                cout << ord[i];\n            }\n            cout << '\\n';\n            for (auto [a, b] : answer_edges[gid]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int POS = N * N;          // 400\nstatic constexpr int NONE = POS;           // 400\nstatic constexpr int BNUM = POS + 1;       // 401\nstatic constexpr int STATES = POS * BNUM;  // 160400\n\nstatic constexpr int INF = 30000;\nstatic constexpr int MAXDIST = 2000; // enough for 40 targets on 20x20\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar dch[4] = {'U', 'D', 'L', 'R'};\n\ninline int sid1(int pos, int b) { return pos * BNUM + b; }\ninline int pos_of_1(int s) { return s / BNUM; }\ninline int block_of_1(int s) { return s % BNUM; }\ninline bool valid_state_1(int pos, int b) { return b == NONE || b != pos; }\n\nint neigh[POS][4];\nunsigned short slide_to_1[BNUM][POS][4];\nstatic vector<unsigned short> revSlide[BNUM][POS];\n\nvector<unsigned short> dist_all;\nstatic vector<int> buckets[MAXDIST + 1];\n\nstruct Action {\n    char a, d;\n};\n\ninline unsigned short* stage_ptr(int k) {\n    return dist_all.data() + (size_t)k * STATES;\n}\n\n// ---------- 2-block temporary model ----------\ninline void canon2(int &b1, int &b2) {\n    if (b1 == NONE) {\n        b2 = NONE;\n        return;\n    }\n    if (b2 == NONE) return;\n    if (b2 < b1) swap(b1, b2);\n}\n\ninline bool valid_state_2(int pos, int b1, int b2) {\n    if (b1 != NONE && b1 == pos) return false;\n    if (b2 != NONE && b2 == pos) return false;\n    return true;\n}\n\ninline int encode2(int pos, int b1, int b2) {\n    // phase-less code\n    return ((b1 * BNUM + b2) * POS + pos);\n}\n\ninline void decode2(int code, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    b1 = t / BNUM;\n}\n\ninline int encodeP(int phase, int pos, int b1, int b2) {\n    return ((((phase * BNUM) + b1) * BNUM + b2) * POS + pos);\n}\n\ninline void decodeP(int code, int &phase, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    t /= BNUM;\n    b1 = t % BNUM;\n    phase = t / BNUM;\n}\n\ninline int slide_to_2(int pos, int b1, int b2, int dir) {\n    int cur = pos;\n    while (true) {\n        int np = neigh[cur][dir];\n        if (np == -1) break;\n        if (np == b1 || np == b2) break;\n        cur = np;\n    }\n    return cur;\n}\n\nvoid precompute() {\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int p = r * N + c;\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                    neigh[p][d] = nr * N + nc;\n                } else {\n                    neigh[p][d] = -1;\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int p = 0; p < POS; p++) {\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; d++) {\n                int cr = r, cc = c;\n                while (true) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) break;\n                    int np = nr * N + nc;\n                    if (b != NONE && np == b) break;\n                    cr = nr;\n                    cc = nc;\n                }\n                slide_to_1[b][p][d] = (unsigned short)(cr * N + cc);\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int q = 0; q < POS; q++) {\n            if (!valid_state_1(q, b)) continue;\n            for (int d = 0; d < 4; d++) {\n                int p = slide_to_1[b][q][d];\n                if (p != q && valid_state_1(p, b)) {\n                    revSlide[b][p].push_back((unsigned short)q);\n                }\n            }\n        }\n    }\n}\n\nvoid compute_stage_dist(int k, const vector<int>& pts, int M) {\n    unsigned short* dist = stage_ptr(k);\n    for (int i = 0; i < STATES; i++) dist[i] = INF;\n    for (int i = 0; i <= MAXDIST; i++) buckets[i].clear();\n\n    int target_next = pts[k + 1];\n    unsigned short* next_dist = (k + 1 < M - 1 ? stage_ptr(k + 1) : nullptr);\n\n    int max_used = 0;\n\n    for (int b = 0; b < BNUM; b++) {\n        if (!valid_state_1(target_next, b)) continue;\n        int s = sid1(target_next, b);\n        unsigned short init_cost = (k + 1 == M - 1 ? 0 : next_dist[s]);\n        dist[s] = init_cost;\n        if (init_cost <= MAXDIST) {\n            buckets[init_cost].push_back(s);\n            max_used = max(max_used, (int)init_cost);\n        }\n    }\n\n    auto relax = [&](int ns, int nd) {\n        if (nd > MAXDIST) return;\n        if (nd < dist[ns]) {\n            dist[ns] = (unsigned short)nd;\n            buckets[nd].push_back(ns);\n            if (nd > max_used) max_used = nd;\n        }\n    };\n\n    for (int cd = 0; cd <= max_used; cd++) {\n        auto &bk = buckets[cd];\n        for (size_t it = 0; it < bk.size(); it++) {\n            int s = bk[it];\n            if (dist[s] != cd) continue;\n\n            int p = pos_of_1(s);\n            int b = block_of_1(s);\n            int nd = cd + 1;\n\n            // reverse of Move\n            for (int d = 0; d < 4; d++) {\n                int q = neigh[p][d];\n                if (q == -1) continue;\n                if (!valid_state_1(q, b)) continue;\n                relax(sid1(q, b), nd);\n            }\n\n            // reverse of Slide\n            for (unsigned short q : revSlide[b][p]) {\n                relax(sid1((int)q, b), nd);\n            }\n\n            // reverse of Alter\n            if (b == NONE) {\n                for (int d = 0; d < 4; d++) {\n                    int a = neigh[p][d];\n                    if (a == -1) continue;\n                    relax(sid1(p, a), nd);\n                }\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    if (neigh[p][d] == b) {\n                        relax(sid1(p, NONE), nd);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid reconstruct_baseline_segment(\n    int k,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    vector<Action>& seg,\n    int& end_block\n) {\n    seg.clear();\n    int target = pts[k + 1];\n    unsigned short* dist = stage_ptr(k);\n\n    int p = start_pos;\n    int b = start_block;\n    int curd = dist[sid1(p, b)];\n\n    while (p != target) {\n        bool found = false;\n\n        auto take = [&](char ac, int dir, int np, int nb) -> bool {\n            if (!valid_state_1(np, nb)) return false;\n            if (dist[sid1(np, nb)] + 1 != curd) return false;\n            seg.push_back({ac, dch[dir]});\n            p = np;\n            b = nb;\n            curd = dist[sid1(p, b)];\n            return true;\n        };\n\n        // prefer slide, then move, then alter\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int sp = slide_to_1[b][p][dir];\n            if (sp != p) found = take('S', dir, sp, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int np = neigh[p][dir];\n            if (np != -1 && np != b) found = take('M', dir, np, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n            if (b == NONE) found = take('A', dir, p, ap);\n            else if (b == ap) found = take('A', dir, p, NONE);\n        }\n\n        if (!found) break; // should not happen\n    }\n\n    end_block = b;\n}\n\nstruct TempNode {\n    int code;         // encoded (phase, pos, b1, b2)\n    int parent;\n    unsigned char op; // 0..11\n    unsigned short dist;\n};\n\n// horizon = 1 or 2\nbool try_improve_horizon(\n    int stage,\n    int horizon,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    int M,\n    int baseline_total,\n    const vector<int>& best_from_checkpoint,\n    vector<Action>& improved_seg,\n    int& improved_end_block\n) {\n    improved_seg.clear();\n    improved_end_block = start_block;\n\n    int end_idx = stage + horizon;\n    int min_future = best_from_checkpoint[end_idx];\n    int gmax = baseline_total - min_future - 1;\n    if (gmax <= 0) return false;\n\n    // Practical cap: enough to capture most useful local improvements\n    gmax = min(gmax, 40);\n\n    vector<TempNode> nodes;\n    nodes.reserve(50000);\n    vector<int> q;\n    q.reserve(50000);\n\n    unordered_map<int, int> id;\n    id.reserve(70000);\n    id.max_load_factor(0.7f);\n\n    auto push_state = [&](int code, int parent, unsigned char op, int nd) {\n        auto it = id.find(code);\n        if (it != id.end()) return;\n        int idx = (int)nodes.size();\n        id.emplace(code, idx);\n        nodes.push_back({code, parent, op, (unsigned short)nd});\n        q.push_back(idx);\n    };\n\n    int b1 = (start_block == NONE ? NONE : start_block);\n    int b2 = NONE;\n    int start_code = encodeP(0, start_pos, b1, b2);\n    push_state(start_code, -1, 255, 0);\n\n    int best_idx = -1;\n    int best_total = baseline_total;\n\n    for (size_t qi = 0; qi < q.size(); qi++) {\n        int idx = q[qi];\n        const auto &nd = nodes[idx];\n\n        int phase, p, x1, x2;\n        decodeP(nd.code, phase, p, x1, x2);\n\n        if (phase == horizon && x2 == NONE) {\n            int endb = x1;\n            int future = (end_idx == M - 1 ? 0 : stage_ptr(end_idx)[sid1(pts[end_idx], endb)]);\n            int total = nd.dist + future;\n            if (total < best_total) {\n                best_total = total;\n                best_idx = idx;\n            }\n        }\n\n        if (nd.dist >= gmax) continue;\n        if ((int)nodes.size() > 180000) break; // emergency cap\n\n        int nextd = nd.dist + 1;\n\n        auto advance_phase = [&](int cur_phase, char act, int np) -> int {\n            if (act == 'A') return cur_phase;\n            if (cur_phase < horizon && np == pts[stage + cur_phase + 1]) return cur_phase + 1;\n            return cur_phase;\n        };\n\n        // Move\n        for (int dir = 0; dir < 4; dir++) {\n            int np = neigh[p][dir];\n            if (np == -1) continue;\n            if (np == x1 || np == x2) continue;\n            int nphase = advance_phase(phase, 'M', np);\n            push_state(encodeP(nphase, np, x1, x2), idx, (unsigned char)(0 + dir), nextd);\n        }\n\n        // Slide\n        for (int dir = 0; dir < 4; dir++) {\n            int sp = slide_to_2(p, x1, x2, dir);\n            if (sp == p) continue;\n            int nphase = advance_phase(phase, 'S', sp);\n            push_state(encodeP(nphase, sp, x1, x2), idx, (unsigned char)(4 + dir), nextd);\n        }\n\n        // Alter\n        for (int dir = 0; dir < 4; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n\n            int nb1 = x1, nb2 = x2;\n\n            if (ap == x1) {\n                if (x2 == NONE) {\n                    nb1 = NONE;\n                    nb2 = NONE;\n                } else {\n                    nb1 = x2;\n                    nb2 = NONE;\n                }\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else if (ap == x2) {\n                nb2 = NONE;\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else {\n                if (x2 == NONE) {\n                    if (x1 == NONE) {\n                        nb1 = ap;\n                        nb2 = NONE;\n                    } else {\n                        nb1 = x1;\n                        nb2 = ap;\n                        canon2(nb1, nb2);\n                    }\n                    if (valid_state_2(p, nb1, nb2)) {\n                        push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n                    }\n                }\n            }\n        }\n    }\n\n    if (best_idx == -1) return false;\n\n    vector<unsigned char> ops;\n    int cur = best_idx;\n    while (nodes[cur].parent != -1) {\n        ops.push_back(nodes[cur].op);\n        cur = nodes[cur].parent;\n    }\n    reverse(ops.begin(), ops.end());\n\n    for (unsigned char op : ops) {\n        char a = (op < 4 ? 'M' : op < 8 ? 'S' : 'A');\n        char d = dch[op & 3];\n        improved_seg.push_back({a, d});\n    }\n\n    int phase, p, y1, y2;\n    decodeP(nodes[best_idx].code, phase, p, y1, y2);\n    improved_end_block = y1;\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    int Nin, M;\n    cin >> Nin >> M;\n    vector<int> pts(M);\n    for (int i = 0; i < M; i++) {\n        int r, c;\n        cin >> r >> c;\n        pts[i] = r * N + c;\n    }\n\n    if (M == 1) return 0;\n\n    dist_all.assign((size_t)(M - 1) * STATES, (unsigned short)INF);\n\n    for (int k = M - 2; k >= 0; k--) {\n        compute_stage_dist(k, pts, M);\n    }\n\n    // best_from_checkpoint[idx]:\n    // minimal remaining cost from position pts[idx] with 0/1 block state\n    // after target idx has just been visited.\n    vector<int> best_from_checkpoint(M, 0);\n    best_from_checkpoint[M - 1] = 0;\n    for (int idx = 1; idx <= M - 2; idx++) {\n        int best = INF;\n        unsigned short* dist = stage_ptr(idx);\n        for (int b = 0; b < BNUM; b++) {\n            if (!valid_state_1(pts[idx], b)) continue;\n            best = min(best, (int)dist[sid1(pts[idx], b)]);\n        }\n        best_from_checkpoint[idx] = best;\n    }\n\n    vector<Action> ans;\n    ans.reserve(1600);\n\n    int cur_pos = pts[0];\n    int cur_block = NONE;\n    int stage = 0;\n\n    while (stage < M - 1) {\n        int baseline_total = stage_ptr(stage)[sid1(cur_pos, cur_block)];\n\n        bool improved = false;\n        vector<Action> seg;\n        int end_block = NONE;\n\n        // First try 2-stage local search (spanning one target boundary)\n        if (stage + 2 <= M - 1) {\n            improved = try_improve_horizon(\n                stage, 2, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 2];\n                cur_block = end_block;\n                stage += 2;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // For the final single stage, try 1-stage temporary 2-block improvement\n        if (stage + 1 == M - 1) {\n            improved = try_improve_horizon(\n                stage, 1, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 1];\n                cur_block = end_block;\n                stage += 1;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // Fallback: exact 1-block baseline, one stage\n        vector<Action> base_seg;\n        int base_end_block = NONE;\n        reconstruct_baseline_segment(stage, cur_pos, cur_block, pts, base_seg, base_end_block);\n        for (auto &x : base_seg) ans.push_back(x);\n        cur_pos = pts[stage + 1];\n        cur_block = base_end_block;\n        stage += 1;\n\n        if ((int)ans.size() > 2 * N * M) break;\n    }\n\n    if ((int)ans.size() > 2 * N * M) {\n        ans.resize(2 * N * M);\n    }\n\n    for (auto &x : ans) {\n        cout << x.a << ' ' << x.d << '\\n';\n    }\n    return 0;\n}"},"8":{"ahc001":"#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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct State {\n    double score;\n    vector<Rect> rects;\n};\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr double TL = 4.95;\n\nint n;\nvector<int> X, Y;\nvector<long long> Rr;\n\nTimer timer;\nmt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline long long area(const Rect& r) {\n    return 1LL * (r.c - r.a) * (r.d - r.b);\n}\n\ninline double sat(long long s, long long r) {\n    double q = (double)min(s, r) / (double)max(s, r);\n    double t = 1.0 - q;\n    return 1.0 - t * t;\n}\n\ninline double local_score(const Rect& r, int i) {\n    return sat(area(r), Rr[i]);\n}\n\ndouble total_score(const vector<Rect>& rects) {\n    double res = 0.0;\n    for (int i = 0; i < n; ++i) res += local_score(rects[i], i);\n    return res;\n}\n\ninline bool hoverlap(const Rect& x, const Rect& y) {\n    return max(x.a, y.a) < min(x.c, y.c);\n}\n\ninline bool voverlap(const Rect& x, const Rect& y) {\n    return max(x.b, y.b) < min(x.d, y.d);\n}\n\nbool legal(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& r = rects[i];\n        if (!(0 <= r.a && r.a < r.c && r.c <= BOARD)) return false;\n        if (!(0 <= r.b && r.b < r.d && r.d <= BOARD)) return false;\n        if (!(r.a <= X[i] && X[i] < r.c)) return false;\n        if (!(r.b <= Y[i] && Y[i] < r.d)) return false;\n    }\n    for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n        if (hoverlap(rects[i], rects[j]) && voverlap(rects[i], rects[j])) return false;\n    }\n    return true;\n}\n\n// ============================================================\n// Initial construction by recursive guillotine partition\n// ============================================================\n\nstruct Cand {\n    long double cost;\n    bool vertical;\n    int k;\n    int cut;\n};\n\nvoid split_rec(const vector<int>& ids, int L, int R, int B, int T,\n               vector<Rect>& leaf_box, bool randomized, long double shape_lambda) {\n    int m = (int)ids.size();\n    if (m == 1) {\n        leaf_box[ids[0]] = {L, B, R, T};\n        return;\n    }\n\n    long long sumR = 0;\n    for (int id : ids) sumR += Rr[id];\n\n    vector<int> sx = ids, sy = ids;\n    sort(sx.begin(), sx.end(), [&](int i, int j) {\n        if (X[i] != X[j]) return X[i] < X[j];\n        return Y[i] < Y[j];\n    });\n    sort(sy.begin(), sy.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    vector<Cand> cands;\n    cands.reserve(2 * (m - 1));\n\n    int W = R - L;\n    int H = T - B;\n\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sx[k - 1]];\n            int minC = X[sx[k - 1]] + 1;\n            int maxC = X[sx[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)L + (long double)W * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int w1 = cut - L;\n            int w2 = R - cut;\n            if (w1 <= 0 || w2 <= 0) continue;\n\n            long double desiredW = (long double)W * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)w1 - desiredW) / (long double)W;\n\n            long double shape = fabsl(log((long double)w1 / (long double)H))\n                              + fabsl(log((long double)w2 / (long double)H));\n\n            cands.push_back({err + shape_lambda * shape, true, k, cut});\n        }\n    }\n\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sy[k - 1]];\n            int minC = Y[sy[k - 1]] + 1;\n            int maxC = Y[sy[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)B + (long double)H * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int h1 = cut - B;\n            int h2 = T - cut;\n            if (h1 <= 0 || h2 <= 0) continue;\n\n            long double desiredH = (long double)H * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)h1 - desiredH) / (long double)H;\n\n            long double shape = fabsl(log((long double)W / (long double)h1))\n                              + fabsl(log((long double)W / (long double)h2));\n\n            cands.push_back({err + shape_lambda * shape, false, k, cut});\n        }\n    }\n\n    if (cands.empty()) {\n        int k = m / 2;\n        int cut = max(X[sx[k - 1]] + 1, min(X[sx[k]], (L + R) / 2));\n        cut = max(L + 1, min(R - 1, cut));\n        vector<int> left(sx.begin(), sx.begin() + k);\n        vector<int> right(sx.begin() + k, sx.end());\n        split_rec(left, L, cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, cut, R, B, T, leaf_box, randomized, shape_lambda);\n        return;\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Cand& p, const Cand& q) {\n        return p.cost < q.cost;\n    });\n\n    int pick = 0;\n    if (randomized) {\n        int top = min<int>(6, cands.size());\n        vector<long long> w(top);\n        long long s = 0;\n        for (int i = 0; i < top; ++i) {\n            w[i] = top - i;\n            s += w[i];\n        }\n        long long z = (long long)(rng() % s);\n        int chosen = 0;\n        while (z >= w[chosen]) {\n            z -= w[chosen];\n            ++chosen;\n        }\n        pick = chosen;\n    }\n\n    Cand best = cands[pick];\n\n    if (best.vertical) {\n        vector<int> left(sx.begin(), sx.begin() + best.k);\n        vector<int> right(sx.begin() + best.k, sx.end());\n        split_rec(left, L, best.cut, B, T, leaf_box, randomized, shape_lambda);\n        split_rec(right, best.cut, R, B, T, leaf_box, randomized, shape_lambda);\n    } else {\n        vector<int> down(sy.begin(), sy.begin() + best.k);\n        vector<int> up(sy.begin() + best.k, sy.end());\n        split_rec(down, L, R, B, best.cut, leaf_box, randomized, shape_lambda);\n        split_rec(up, L, R, best.cut, T, leaf_box, randomized, shape_lambda);\n    }\n}\n\nRect place_inside_box(const Rect& box, int id) {\n    int W = box.c - box.a;\n    int H = box.d - box.b;\n    long long boxA = 1LL * W * H;\n    long long target = Rr[id];\n\n    if (boxA <= target) return box;\n\n    long long bestA = -1;\n    int bestW = 1, bestH = 1;\n    long long bestShape = (1LL << 60);\n\n    for (int w = 1; w <= W; ++w) {\n        long long h = min<long long>(H, target / w);\n        if (h <= 0) continue;\n        long long a = 1LL * w * h;\n        long long shp = llabs((long long)w - h);\n        if (a > bestA || (a == bestA && shp < bestShape)) {\n            bestA = a;\n            bestW = w;\n            bestH = (int)h;\n            bestShape = shp;\n        }\n    }\n\n    int loA = max(box.a, X[id] + 1 - bestW);\n    int hiA = min(X[id], box.c - bestW);\n    int a = clamp(X[id] - bestW / 2, loA, hiA);\n    int c = a + bestW;\n\n    int loB = max(box.b, Y[id] + 1 - bestH);\n    int hiB = min(Y[id], box.d - bestH);\n    int b = clamp(Y[id] - bestH / 2, loB, hiB);\n    int d = b + bestH;\n\n    return {a, b, c, d};\n}\n\nvector<Rect> build_solution(bool randomized) {\n    vector<int> ids(n);\n    iota(ids.begin(), ids.end(), 0);\n\n    long double shape_lambda;\n    if (!randomized) {\n        shape_lambda = 0.0015L;\n    } else {\n        int t = (int)(rng() % 5);\n        if (t == 0) shape_lambda = 0.0L;\n        else if (t == 1) shape_lambda = 0.0008L;\n        else if (t == 2) shape_lambda = 0.0015L;\n        else if (t == 3) shape_lambda = 0.0030L;\n        else shape_lambda = 0.0050L;\n    }\n\n    vector<Rect> boxes(n);\n    split_rec(ids, 0, BOARD, 0, BOARD, boxes, randomized, shape_lambda);\n\n    vector<Rect> rects(n);\n    for (int i = 0; i < n; ++i) rects[i] = place_inside_box(boxes[i], i);\n    return rects;\n}\n\n// ============================================================\n// Cheap side-wise local hill climbing\n// ============================================================\n\nstruct Op {\n    double gain = 0.0;\n    Rect nr;\n};\n\nvector<int> candidate_steps(long long diff, int dim, int tmax) {\n    vector<int> cand;\n    cand.reserve(20);\n    cand.push_back(1);\n    cand.push_back(tmax);\n\n    long double q = (long double)diff / (long double)dim;\n    long long f = (long long)floor((double)q);\n    long long c = (long long)ceil((double)q);\n    for (int d = -2; d <= 2; ++d) {\n        cand.push_back((int)(f + d));\n        cand.push_back((int)(c + d));\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    vector<int> res;\n    for (int t : cand) if (1 <= t && t <= tmax) res.push_back(t);\n    return res;\n}\n\nOp best_operation_for(int i, const vector<Rect>& rects) {\n    const Rect& curR = rects[i];\n    long long s = area(curR);\n    long long target = Rr[i];\n    double curSat = sat(s, target);\n\n    Op best;\n    best.nr = curR;\n\n    int w = curR.c - curR.a;\n    int h = curR.d - curR.b;\n\n    if (s < target) {\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].c <= curR.a) bound = max(bound, rects[j].c);\n            }\n            int tmax = curR.a - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].a >= curR.c) bound = min(bound, rects[j].a);\n            }\n            int tmax = bound - curR.c;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].d <= curR.b) bound = max(bound, rects[j].d);\n            }\n            int tmax = curR.b - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].b >= curR.d) bound = min(bound, rects[j].b);\n            }\n            int tmax = bound - curR.d;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    if (s > target) {\n        {\n            int tmax = X[i] - curR.a;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = curR.c - (X[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = Y[i] - curR.b;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = curR.d - (Y[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid side_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            double sc = local_score(rects[i], i);\n            double noise = (double)(rng() & 1023) * 1e-12;\n            ord.push_back({sc + noise, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        for (auto [_, i] : ord) {\n            if (timer.elapsed() >= end_time) break;\n            while (timer.elapsed() < end_time) {\n                Op op = best_operation_for(i, rects);\n                if (op.gain <= 1e-15) break;\n                rects[i] = op.nr;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Moderate exact single-rectangle optimization\n// ============================================================\n\nRect exact_best_for(int i, const vector<Rect>& rects) {\n    const Rect& cur = rects[i];\n    const long long target = Rr[i];\n    const int px = X[i];\n    const int py = Y[i];\n\n    Rect best = cur;\n    double bestSc = local_score(cur, i);\n\n    auto upd = [&](const Rect& cand) {\n        double sc = local_score(cand, i);\n        if (sc > bestSc + 1e-15) {\n            bestSc = sc;\n            best = cand;\n        } else if (fabs(sc - bestSc) <= 1e-15) {\n            long long da = llabs(area(cand) - target);\n            long long db = llabs(area(best) - target);\n            if (da < db) best = cand;\n        }\n    };\n\n    auto try_width = [&](int b, int d, int left, int right) {\n        if (!(b <= py && py < d)) return;\n        int H = d - b;\n        int maxW = right - left;\n        if (H <= 0 || maxW <= 0) return;\n\n        vector<int> ws;\n        ws.reserve(16);\n        ws.push_back(1);\n        ws.push_back(maxW);\n        ws.push_back(cur.c - cur.a);\n\n        long double ideal = (long double)target / (long double)H;\n        long long f = (long long)floor((double)ideal);\n        long long c = (long long)ceil((double)ideal);\n        for (int dt = -2; dt <= 2; ++dt) {\n            ws.push_back((int)(f + dt));\n            ws.push_back((int)(c + dt));\n        }\n\n        sort(ws.begin(), ws.end());\n        ws.erase(unique(ws.begin(), ws.end()), ws.end());\n\n        for (int w : ws) {\n            if (w < 1 || w > maxW) continue;\n            int loA = max(left, px + 1 - w);\n            int hiA = min(px, right - w);\n            if (loA > hiA) continue;\n            int pref = cur.a;\n            if (pref < loA || pref > hiA) pref = px - w / 2;\n            int a = clamp(pref, loA, hiA);\n            upd(Rect{a, b, a + w, d});\n        }\n    };\n\n    auto try_height = [&](int a, int c, int bot, int top) {\n        if (!(a <= px && px < c)) return;\n        int W = c - a;\n        int maxH = top - bot;\n        if (W <= 0 || maxH <= 0) return;\n\n        vector<int> hs;\n        hs.reserve(16);\n        hs.push_back(1);\n        hs.push_back(maxH);\n        hs.push_back(cur.d - cur.b);\n\n        long double ideal = (long double)target / (long double)W;\n        long long f = (long long)floor((double)ideal);\n        long long cc = (long long)ceil((double)ideal);\n        for (int dt = -2; dt <= 2; ++dt) {\n            hs.push_back((int)(f + dt));\n            hs.push_back((int)(cc + dt));\n        }\n\n        sort(hs.begin(), hs.end());\n        hs.erase(unique(hs.begin(), hs.end()), hs.end());\n\n        for (int h : hs) {\n            if (h < 1 || h > maxH) continue;\n            int loB = max(bot, py + 1 - h);\n            int hiB = min(py, top - h);\n            if (loB > hiB) continue;\n            int pref = cur.b;\n            if (pref < loB || pref > hiB) pref = py - h / 2;\n            int b = clamp(pref, loB, hiB);\n            upd(Rect{a, b, c, b + h});\n        }\n    };\n\n    {\n        vector<int> bottoms, tops;\n        bottoms.reserve(n + 8);\n        tops.reserve(n + 8);\n\n        bottoms.push_back(0);\n        bottoms.push_back(py);\n        bottoms.push_back(cur.b);\n\n        tops.push_back(BOARD);\n        tops.push_back(py + 1);\n        tops.push_back(cur.d);\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            if (rects[j].d <= py) bottoms.push_back(rects[j].d);\n            if (rects[j].b > py) tops.push_back(rects[j].b);\n        }\n\n        sort(bottoms.begin(), bottoms.end());\n        bottoms.erase(unique(bottoms.begin(), bottoms.end()), bottoms.end());\n        sort(tops.begin(), tops.end());\n        tops.erase(unique(tops.begin(), tops.end()), tops.end());\n\n        for (int b : bottoms) {\n            if (b > py) continue;\n            for (int d : tops) {\n                if (d <= py || b >= d) continue;\n\n                int left = 0, right = BOARD;\n                bool bad = false;\n\n                for (int j = 0; j < n; ++j) if (j != i) {\n                    const Rect& o = rects[j];\n                    if (o.d <= b || d <= o.b) continue;\n                    if (o.a <= px && px < o.c) {\n                        bad = true;\n                        break;\n                    }\n                    if (o.c <= px) left = max(left, o.c);\n                    else if (o.a > px) right = min(right, o.a);\n                }\n                if (bad || left >= right) continue;\n\n                try_width(b, d, left, right);\n            }\n        }\n    }\n\n    {\n        vector<int> lefts, rights;\n        lefts.reserve(n + 8);\n        rights.reserve(n + 8);\n\n        lefts.push_back(0);\n        lefts.push_back(px);\n        lefts.push_back(cur.a);\n\n        rights.push_back(BOARD);\n        rights.push_back(px + 1);\n        rights.push_back(cur.c);\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            if (rects[j].c <= px) lefts.push_back(rects[j].c);\n            if (rects[j].a > px) rights.push_back(rects[j].a);\n        }\n\n        sort(lefts.begin(), lefts.end());\n        lefts.erase(unique(lefts.begin(), lefts.end()), lefts.end());\n        sort(rights.begin(), rights.end());\n        rights.erase(unique(rights.begin(), rights.end()), rights.end());\n\n        for (int a : lefts) {\n            if (a > px) continue;\n            for (int c : rights) {\n                if (c <= px || a >= c) continue;\n\n                int bot = 0, top = BOARD;\n                bool bad = false;\n\n                for (int j = 0; j < n; ++j) if (j != i) {\n                    const Rect& o = rects[j];\n                    if (o.c <= a || c <= o.a) continue;\n                    if (o.b <= py && py < o.d) {\n                        bad = true;\n                        break;\n                    }\n                    if (o.d <= py) bot = max(bot, o.d);\n                    else if (o.b > py) top = min(top, o.b);\n                }\n                if (bad || bot >= top) continue;\n\n                try_height(a, c, bot, top);\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid exact_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) ord.push_back({local_score(rects[i], i), i});\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        int K = min(n, (n <= 80 ? 12 : 8));\n\n        for (int z = 0; z < K; ++z) {\n            if (timer.elapsed() >= end_time) break;\n            int i = ord[z].second;\n\n            Rect nr = exact_best_for(i, rects);\n            if (local_score(nr, i) > local_score(rects[i], i) + 1e-15) {\n                rects[i] = nr;\n                changed = true;\n\n                while (timer.elapsed() < end_time) {\n                    Op op = best_operation_for(i, rects);\n                    if (op.gain <= 1e-15) break;\n                    rects[i] = op.nr;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Pairwise cut optimization for clean adjacent pairs\n// ============================================================\n\nstruct PairMove {\n    double gain = 0.0;\n    int i = -1, j = -1;\n    Rect ri, rj;\n};\n\nvector<int> around_candidates(long long v, int lo, int hi) {\n    vector<int> res;\n    for (int d = -3; d <= 3; ++d) {\n        long long x = v + d;\n        if (lo <= x && x <= hi) res.push_back((int)x);\n    }\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nPairMove best_pair_move(const vector<Rect>& rects) {\n    PairMove best;\n\n    for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n        const Rect& A = rects[i];\n        const Rect& B = rects[j];\n\n        if (A.b == B.b && A.d == B.d && (A.c == B.a || B.c == A.a)) {\n            int l = i, r = j;\n            Rect RL = A, RR = B;\n            if (RL.a > RR.a) {\n                swap(l, r);\n                swap(RL, RR);\n            }\n\n            int L = RL.a, R = RR.c, Btm = RL.b, Top = RL.d;\n            int H = Top - Btm;\n            if (H > 0) {\n                int lo = max(L + 1, X[l] + 1);\n                int hi = min(R - 1, X[r]);\n                if (lo <= hi) {\n                    double cur = local_score(RL, l) + local_score(RR, r);\n                    vector<int> cand = {lo, hi, RL.c};\n\n                    long long w1f = Rr[l] / H;\n                    long long w1c = (Rr[l] + H - 1) / H;\n                    long long cut1 = L + w1f;\n                    long long cut2 = L + w1c;\n                    auto v1 = around_candidates(cut1, lo, hi);\n                    auto v2 = around_candidates(cut2, lo, hi);\n                    cand.insert(cand.end(), v1.begin(), v1.end());\n                    cand.insert(cand.end(), v2.begin(), v2.end());\n\n                    long long w2f = Rr[r] / H;\n                    long long w2c = (Rr[r] + H - 1) / H;\n                    long long cut3 = R - w2f;\n                    long long cut4 = R - w2c;\n                    auto v3 = around_candidates(cut3, lo, hi);\n                    auto v4 = around_candidates(cut4, lo, hi);\n                    cand.insert(cand.end(), v3.begin(), v3.end());\n                    cand.insert(cand.end(), v4.begin(), v4.end());\n\n                    sort(cand.begin(), cand.end());\n                    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n                    for (int cut : cand) {\n                        Rect nL{L, Btm, cut, Top};\n                        Rect nR{cut, Btm, R, Top};\n                        double nxt = local_score(nL, l) + local_score(nR, r);\n                        double gain = nxt - cur;\n                        if (gain > best.gain + 1e-15) {\n                            best.gain = gain;\n                            best.i = l;\n                            best.j = r;\n                            best.ri = nL;\n                            best.rj = nR;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (A.a == B.a && A.c == B.c && (A.d == B.b || B.d == A.b)) {\n            int dwn = i, up = j;\n            Rect RD = A, RU = B;\n            if (RD.b > RU.b) {\n                swap(dwn, up);\n                swap(RD, RU);\n            }\n\n            int L = RD.a, R = RD.c, Btm = RD.b, Top = RU.d;\n            int W = R - L;\n            if (W > 0) {\n                int lo = max(Btm + 1, Y[dwn] + 1);\n                int hi = min(Top - 1, Y[up]);\n                if (lo <= hi) {\n                    double cur = local_score(RD, dwn) + local_score(RU, up);\n                    vector<int> cand = {lo, hi, RD.d};\n\n                    long long h1f = Rr[dwn] / W;\n                    long long h1c = (Rr[dwn] + W - 1) / W;\n                    long long cut1 = Btm + h1f;\n                    long long cut2 = Btm + h1c;\n                    auto v1 = around_candidates(cut1, lo, hi);\n                    auto v2 = around_candidates(cut2, lo, hi);\n                    cand.insert(cand.end(), v1.begin(), v1.end());\n                    cand.insert(cand.end(), v2.begin(), v2.end());\n\n                    long long h2f = Rr[up] / W;\n                    long long h2c = (Rr[up] + W - 1) / W;\n                    long long cut3 = Top - h2f;\n                    long long cut4 = Top - h2c;\n                    auto v3 = around_candidates(cut3, lo, hi);\n                    auto v4 = around_candidates(cut4, lo, hi);\n                    cand.insert(cand.end(), v3.begin(), v3.end());\n                    cand.insert(cand.end(), v4.begin(), v4.end());\n\n                    sort(cand.begin(), cand.end());\n                    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n                    for (int cut : cand) {\n                        Rect nD{L, Btm, R, cut};\n                        Rect nU{L, cut, R, Top};\n                        double nxt = local_score(nD, dwn) + local_score(nU, up);\n                        double gain = nxt - cur;\n                        if (gain > best.gain + 1e-15) {\n                            best.gain = gain;\n                            best.i = dwn;\n                            best.j = up;\n                            best.ri = nD;\n                            best.rj = nU;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid pairwise_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        PairMove mv = best_pair_move(rects);\n        if (mv.gain <= 1e-15) break;\n\n        rects[mv.i] = mv.ri;\n        rects[mv.j] = mv.rj;\n\n        while (timer.elapsed() < end_time) {\n            Op op = best_operation_for(mv.i, rects);\n            if (op.gain <= 1e-15) break;\n            rects[mv.i] = op.nr;\n        }\n        while (timer.elapsed() < end_time) {\n            Op op = best_operation_for(mv.j, rects);\n            if (op.gain <= 1e-15) break;\n            rects[mv.j] = op.nr;\n        }\n    }\n}\n\nvoid add_state(vector<State>& states, vector<Rect> rects) {\n    if (!legal(rects)) return;\n    double sc = total_score(rects);\n    states.push_back({sc, std::move(rects)});\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)states.size() > 4) states.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    X.resize(n);\n    Y.resize(n);\n    Rr.resize(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> X[i] >> Y[i] >> Rr[i];\n    }\n\n    vector<State> states;\n    vector<Rect> safe_baseline = build_solution(false);\n    if (!legal(safe_baseline)) {\n        safe_baseline.resize(n);\n        for (int i = 0; i < n; ++i) safe_baseline[i] = {X[i], Y[i], X[i] + 1, Y[i] + 1};\n    }\n    add_state(states, safe_baseline);\n\n    double init_end = 0.85;\n    while (timer.elapsed() < init_end) {\n        add_state(states, build_solution(true));\n    }\n\n    double polish_end = 2.25;\n    for (int i = 0; i < (int)states.size(); ++i) {\n        double now = timer.elapsed();\n        if (now >= polish_end) break;\n        double slice = (polish_end - now) / (double)(states.size() - i);\n        side_improve(states[i].rects, now + slice);\n        if (!legal(states[i].rects)) states[i].rects = safe_baseline;\n        states[i].score = total_score(states[i].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    int finalists = min<int>(2, states.size());\n\n    double exact_end = 3.95;\n    for (int k = 0; k < finalists; ++k) {\n        double now = timer.elapsed();\n        if (now >= exact_end) break;\n        double slice = (exact_end - now) / (double)(finalists - k);\n        exact_improve(states[k].rects, now + slice);\n        if (!legal(states[k].rects)) states[k].rects = safe_baseline;\n        states[k].score = total_score(states[k].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    double pair_end = 4.65;\n    for (int k = 0; k < finalists; ++k) {\n        double now = timer.elapsed();\n        if (now >= pair_end) break;\n        double slice = (pair_end - now) / (double)(finalists - k);\n        pairwise_improve(states[k].rects, now + slice);\n        if (!legal(states[k].rects)) states[k].rects = safe_baseline;\n        states[k].score = total_score(states[k].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<Rect> best = states[0].rects;\n\n    // Small post-pairwise exact pass on the final winner.\n    exact_improve(best, 4.82);\n    if (!legal(best)) best = states[0].rects;\n\n    side_improve(best, TL);\n\n    if (!legal(best)) {\n        bool found = false;\n        for (auto& st : states) {\n            if (legal(st.rects)) {\n                best = st.rects;\n                found = true;\n                break;\n            }\n        }\n        if (!found) best = safe_baseline;\n    }\n\n    for (int i = 0; i < n; ++i) {\n        cout << best[i].a << ' ' << best[i].b << ' ' << best[i].c << ' ' << best[i].d << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int C = N * N;\n    static constexpr int FORCE_CAP = 16;\n    static constexpr double TL = 1.92;\n\n    int si, sj, start;\n    array<int, C> tile{};\n    array<int, C> val{};\n    array<array<int, 4>, C> adj{};\n    array<uint8_t, C> deg{};\n\n    int M = 0;\n\n    vector<int> tileSize;\n    vector<int> tileSum;\n    vector<int> tileMax;\n    vector<int> tileExp2; // expected tile contribution * 2\n    vector<int> tileUB;   // optimistic UB contribution\n\n    vector<unsigned char> vis;\n\n    vector<int> cellSeen;\n    vector<int> cellComp;\n    vector<int> tileSeen;\n    int evalStamp = 1;\n    int tileStamp = 1;\n\n    array<int, C> qbuf{};\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n\n    struct Params {\n        int wExp2;\n        int wUb;\n        int wTiles;\n        int wImm;\n        int wBranches;\n        int wDeg;\n        double q;\n        int exactLimit;\n        int exactNodeLimit;\n    };\n\n    struct ReachInfo {\n        int selExp2 = 0;\n        int selUb = 0;\n        int selTiles = 0;\n\n        int maxUb = 0;\n        int maxTiles = 0;\n\n        int branches = 0;\n        int availDeg = 0;\n    };\n\n    struct Cand {\n        int to = -1;\n        int eval = 0;\n        int imm = 0;\n        int exp2 = 0;\n        int ub = 0;\n        int tiles = 0;\n        int branches = 0;\n        int availDeg = 0;\n\n        int endCell = -1;\n        uint8_t plen = 0;\n        array<int, FORCE_CAP> path{};\n    };\n\n    struct Solution {\n        vector<int> seq;\n        vector<int> pref;\n        int score = 0;\n        uint64_t hash = 0;\n    };\n\n    vector<Solution> elite;\n    Solution bestSol;\n\n    // exact suffix search\n    vector<int> exactBestPath;\n    vector<int> exactCurPath;\n    int exactBestScore = 0;\n    bool exactAbort = false;\n    int exactNodes = 0;\n    int exactNodeLimitNow = 0;\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int r, int c) const { return r * N + c; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    template <class Used>\n    inline int list_legal(int cur, const Used& used, int out[4]) const {\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            if (!used[tile[nx]]) out[cc++] = nx;\n        }\n        return cc;\n    }\n\n    void read_input() {\n        cin >> si >> sj;\n        start = id(si, sj);\n\n        int mxTile = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int t;\n                cin >> t;\n                tile[id(r, c)] = t;\n                mxTile = max(mxTile, t);\n            }\n        }\n        M = mxTile + 1;\n\n        tileSize.assign(M, 0);\n        tileSum.assign(M, 0);\n        tileMax.assign(M, 0);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p;\n                cin >> p;\n                int v = id(r, c);\n                val[v] = p;\n                int t = tile[v];\n                tileSize[t]++;\n                tileSum[t] += p;\n                tileMax[t] = max(tileMax[t], p);\n            }\n        }\n\n        tileExp2.assign(M, 0);\n        tileUB.assign(M, 0);\n        for (int t = 0; t < M; t++) {\n            if (tileSize[t] == 1) {\n                tileExp2[t] = tileSum[t] * 2;\n                tileUB[t] = tileSum[t];\n            } else {\n                // Domino: optimistic bound is max cell, expected heuristic is average.\n                // In *2 scale, average is tileSum.\n                tileExp2[t] = tileSum[t];\n                tileUB[t] = tileMax[t];\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                int d = 0;\n                const int dr[4] = {-1, 1, 0, 0};\n                const int dc[4] = {0, 0, -1, 1};\n                for (int k = 0; k < 4; k++) {\n                    int nr = r + dr[k], nc = c + dc[k];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    int u = id(nr, nc);\n                    if (tile[u] == tile[v]) continue;\n                    adj[v][d++] = u;\n                }\n                deg[v] = (uint8_t)d;\n            }\n        }\n\n        vis.assign(M, 0);\n        cellSeen.assign(C, 0);\n        cellComp.assign(C, -1);\n        tileSeen.assign(M, 0);\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : seq) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    static bool cand_cmp(const Cand& a, const Cand& b) {\n        if (a.eval != b.eval) return a.eval > b.eval;\n        if (a.tiles != b.tiles) return a.tiles > b.tiles;\n        if (a.exp2 != b.exp2) return a.exp2 > b.exp2;\n        if (a.imm != b.imm) return a.imm > b.imm;\n        if (a.branches != b.branches) return a.branches > b.branches;\n        return a.availDeg > b.availDeg;\n    }\n\n    Params sample_params() {\n        Params p;\n        p.wExp2 = rng.next_int(5, 8);\n        p.wUb = rng.next_int(1, 3);\n        p.wTiles = rng.next_int(50, 120);\n        p.wImm = rng.next_int(14, 24);\n        p.wBranches = rng.next_int(20, 90);\n        p.wDeg = rng.next_int(8, 28);\n        p.q = 0.06 + 0.24 * rng.next_double();\n\n        double e = elapsed();\n        if (e < 0.70) {\n            p.exactLimit = 22;\n            p.exactNodeLimit = 32000;\n        } else if (e < 1.30) {\n            p.exactLimit = 20;\n            p.exactNodeLimit = 22000;\n        } else {\n            p.exactLimit = 18;\n            p.exactNodeLimit = 14000;\n        }\n        return p;\n    }\n\n    inline int comp_metric(int exp2, int ub, int tiles, const Params& par) const {\n        return par.wExp2 * exp2 + par.wUb * ub + par.wTiles * tiles;\n    }\n\n    ReachInfo analyze_from_cell(int cell, const vector<unsigned char>& used, int forbidTile, const Params& par) {\n        ++evalStamp;\n\n        int compExp2[4];\n        int compUb[4];\n        int compTiles[4];\n        int compCnt = 0;\n\n        int branchIds[4];\n        int branchCnt = 0;\n\n        ReachInfo res;\n        int bestMetric = -1;\n\n        for (int i = 0; i < deg[cell]; i++) {\n            int s = adj[cell][i];\n            int ts = tile[s];\n            if (used[ts] || ts == forbidTile) continue;\n\n            res.availDeg++;\n\n            if (cellSeen[s] != evalStamp) {\n                int cid = compCnt++;\n                int qh = 0, qt = 0;\n                qbuf[qt++] = s;\n                cellSeen[s] = evalStamp;\n                cellComp[s] = cid;\n\n                ++tileStamp;\n                int exp2 = 0, ub = 0, tilesCnt = 0;\n\n                while (qh < qt) {\n                    int v = qbuf[qh++];\n                    int tv = tile[v];\n                    if (tileSeen[tv] != tileStamp) {\n                        tileSeen[tv] = tileStamp;\n                        exp2 += tileExp2[tv];\n                        ub += tileUB[tv];\n                        tilesCnt++;\n                    }\n                    for (int j = 0; j < deg[v]; j++) {\n                        int u = adj[v][j];\n                        int tu = tile[u];\n                        if (used[tu] || tu == forbidTile) continue;\n                        if (cellSeen[u] == evalStamp) continue;\n                        cellSeen[u] = evalStamp;\n                        cellComp[u] = cid;\n                        qbuf[qt++] = u;\n                    }\n                }\n\n                compExp2[cid] = exp2;\n                compUb[cid] = ub;\n                compTiles[cid] = tilesCnt;\n            }\n\n            int cid = cellComp[s];\n            int metric = comp_metric(compExp2[cid], compUb[cid], compTiles[cid], par);\n            if (metric > bestMetric ||\n                (metric == bestMetric && compTiles[cid] > res.selTiles) ||\n                (metric == bestMetric && compTiles[cid] == res.selTiles && compUb[cid] > res.selUb)) {\n                bestMetric = metric;\n                res.selExp2 = compExp2[cid];\n                res.selUb = compUb[cid];\n                res.selTiles = compTiles[cid];\n            }\n\n            res.maxUb = max(res.maxUb, compUb[cid]);\n            res.maxTiles = max(res.maxTiles, compTiles[cid]);\n\n            bool exists = false;\n            for (int b = 0; b < branchCnt; b++) {\n                if (branchIds[b] == cid) {\n                    exists = true;\n                    break;\n                }\n            }\n            if (!exists) branchIds[branchCnt++] = cid;\n        }\n\n        res.branches = branchCnt;\n        return res;\n    }\n\n    inline int candidate_eval(int gain, const ReachInfo& ri, const Params& par) const {\n        return par.wImm * gain\n             + par.wExp2 * ri.selExp2\n             + par.wUb * ri.selUb\n             + par.wTiles * ri.selTiles\n             + par.wBranches * ri.branches\n             + par.wDeg * ri.availDeg;\n    }\n\n    Cand build_macro_candidate(int first, vector<unsigned char>& used, const Params& par) {\n        Cand c;\n        c.to = first;\n\n        int marked[FORCE_CAP];\n        int mc = 0;\n\n        int cur = first;\n        while (true) {\n            int t = tile[cur];\n            used[t] = 1;\n            marked[mc++] = t;\n            c.path[c.plen++] = cur;\n            c.imm += val[cur];\n\n            if (c.plen >= FORCE_CAP) {\n                ReachInfo ri = analyze_from_cell(cur, used, -1, par);\n                c.exp2 = ri.selExp2;\n                c.ub = ri.selUb;\n                c.tiles = ri.selTiles;\n                c.branches = ri.branches;\n                c.availDeg = ri.availDeg;\n                c.endCell = cur;\n                c.eval = candidate_eval(c.imm, ri, par);\n                break;\n            }\n\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n            if (cc == 1) {\n                cur = nxts[0];\n                continue;\n            } else if (cc == 0) {\n                c.endCell = cur;\n                c.eval = par.wImm * c.imm;\n                break;\n            } else {\n                ReachInfo ri = analyze_from_cell(cur, used, -1, par);\n                c.exp2 = ri.selExp2;\n                c.ub = ri.selUb;\n                c.tiles = ri.selTiles;\n                c.branches = ri.branches;\n                c.availDeg = ri.availDeg;\n                c.endCell = cur;\n                c.eval = candidate_eval(c.imm, ri, par);\n                break;\n            }\n        }\n\n        for (int i = 0; i < mc; i++) used[marked[i]] = 0;\n        return c;\n    }\n\n    void apply_macro(const Cand& c, vector<int>& seq, int& score) {\n        for (int i = 0; i < c.plen; i++) {\n            int v = c.path[i];\n            vis[tile[v]] = 1;\n            seq.push_back(v);\n            score += val[v];\n        }\n    }\n\n    vector<int> greedy_suffix_small(int cur, vector<unsigned char> used, const Params& par, int& outScore) {\n        vector<int> path;\n        outScore = 0;\n\n        while (true) {\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n            if (cc == 0) break;\n\n            if (cc == 1) {\n                int nx = nxts[0];\n                used[tile[nx]] = 1;\n                path.push_back(nx);\n                outScore += val[nx];\n                cur = nx;\n                continue;\n            }\n\n            Cand cs[4];\n            for (int i = 0; i < cc; i++) cs[i] = build_macro_candidate(nxts[i], used, par);\n            sort(cs, cs + cc, cand_cmp);\n\n            for (int i = 0; i < cs[0].plen; i++) {\n                int v = cs[0].path[i];\n                used[tile[v]] = 1;\n                path.push_back(v);\n                outScore += val[v];\n                cur = v;\n            }\n        }\n        return path;\n    }\n\n    void exact_dfs(int cur, vector<unsigned char>& used, int curScore, const Params& par) {\n        int forcedAdded = 0;\n\n        // Compress deterministic corridor exactly.\n        while (true) {\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n\n            if (cc == 0) {\n                if (curScore > exactBestScore) {\n                    exactBestScore = curScore;\n                    exactBestPath = exactCurPath;\n                }\n                for (int k = 0; k < forcedAdded; k++) {\n                    used[tile[exactCurPath.back()]] = 0;\n                    exactCurPath.pop_back();\n                }\n                return;\n            }\n            if (cc >= 2) break;\n\n            int nx = nxts[0];\n            used[tile[nx]] = 1;\n            exactCurPath.push_back(nx);\n            curScore += val[nx];\n            cur = nx;\n            forcedAdded++;\n        }\n\n        if ((++exactNodes & 255) == 0) {\n            if (exactNodes > exactNodeLimitNow || elapsed() > TL) {\n                exactAbort = true;\n                for (int k = 0; k < forcedAdded; k++) {\n                    used[tile[exactCurPath.back()]] = 0;\n                    exactCurPath.pop_back();\n                }\n                return;\n            }\n        }\n\n        ReachInfo ub = analyze_from_cell(cur, used, -1, par);\n        if (curScore + ub.maxUb <= exactBestScore) {\n            for (int k = 0; k < forcedAdded; k++) {\n                used[tile[exactCurPath.back()]] = 0;\n                exactCurPath.pop_back();\n            }\n            return;\n        }\n\n        Cand cs[4];\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            int tnx = tile[nx];\n            if (used[tnx]) continue;\n            ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n            int ev = candidate_eval(val[nx], ri, par);\n            cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n        }\n\n        if (cc > 1) sort(cs, cs + cc, cand_cmp);\n\n        for (int i = 0; i < cc; i++) {\n            int nx = cs[i].to;\n            int tnx = tile[nx];\n            used[tnx] = 1;\n            exactCurPath.push_back(nx);\n            exact_dfs(nx, used, curScore + val[nx], par);\n            exactCurPath.pop_back();\n            used[tnx] = 0;\n            if (exactAbort) break;\n        }\n\n        for (int k = 0; k < forcedAdded; k++) {\n            used[tile[exactCurPath.back()]] = 0;\n            exactCurPath.pop_back();\n        }\n    }\n\n    vector<int> exact_finish(int cur, vector<unsigned char>& used, const Params& par) {\n        exactBestPath.clear();\n        exactCurPath.clear();\n        exactBestScore = 0;\n        exactAbort = false;\n        exactNodes = 0;\n        exactNodeLimitNow = par.exactNodeLimit;\n\n        int greedyScore = 0;\n        exactBestPath = greedy_suffix_small(cur, used, par, greedyScore);\n        exactBestScore = greedyScore;\n\n        exact_dfs(cur, used, 0, par);\n        return exactBestPath;\n    }\n\n    void build_prefix_state(const Solution& base, int cutIdx, vector<int>& seq, int& score) {\n        fill(vis.begin(), vis.end(), 0);\n        seq.clear();\n        seq.reserve(C);\n\n        for (int i = 0; i <= cutIdx; i++) {\n            int v = base.seq[i];\n            seq.push_back(v);\n            vis[tile[v]] = 1;\n        }\n        score = base.pref[cutIdx];\n    }\n\n    pair<vector<int>, int> grow_from(const Solution& base, int cutIdx, const Params& par) {\n        vector<int> seq;\n        int score = 0;\n        build_prefix_state(base, cutIdx, seq, score);\n\n        int cur = seq.back();\n\n        while (true) {\n            if (elapsed() > TL) break;\n\n            // Deterministic corridor compression.\n            while (true) {\n                int nxts[4];\n                int cc = list_legal(cur, vis, nxts);\n                if (cc == 0) return {seq, score};\n                if (cc >= 2) break;\n\n                int nx = nxts[0];\n                vis[tile[nx]] = 1;\n                seq.push_back(nx);\n                score += val[nx];\n                cur = nx;\n                if (elapsed() > TL) return {seq, score};\n            }\n\n            ReachInfo curInfo = analyze_from_cell(cur, vis, -1, par);\n            if (curInfo.maxTiles <= par.exactLimit && elapsed() < TL - 0.02) {\n                vector<int> suf = exact_finish(cur, vis, par);\n                for (int nx : suf) {\n                    vis[tile[nx]] = 1;\n                    seq.push_back(nx);\n                    score += val[nx];\n                    cur = nx;\n                }\n                break;\n            }\n\n            int nxts[4];\n            int cc = list_legal(cur, vis, nxts);\n            if (cc == 0) break;\n\n            Cand cs[4];\n            for (int i = 0; i < cc; i++) cs[i] = build_macro_candidate(nxts[i], vis, par);\n            if (cc > 1) sort(cs, cs + cc, cand_cmp);\n\n            int pick = 0;\n            if (cc >= 2) {\n                int gap = cs[0].eval - cs[1].eval;\n                double q = par.q;\n                if (gap > 3000) q *= 0.05;\n                else if (gap > 1500) q *= 0.15;\n                else if (gap > 700) q *= 0.35;\n                else if (gap > 300) q *= 0.60;\n                else if (gap > 100) q *= 0.85;\n                else q *= 1.15;\n                if (q > 0.85) q = 0.85;\n\n                while (pick + 1 < cc && rng.next_double() < q) pick++;\n            }\n\n            apply_macro(cs[pick], seq, score);\n            cur = seq.back();\n        }\n\n        return {seq, score};\n    }\n\n    Solution make_solution(const vector<int>& seq, int score) {\n        Solution s;\n        s.seq = seq;\n        s.score = score;\n        s.pref.resize(seq.size());\n        int sum = 0;\n        for (int i = 0; i < (int)seq.size(); i++) {\n            sum += val[seq[i]];\n            s.pref[i] = sum;\n        }\n        s.hash = hash_seq(seq);\n        return s;\n    }\n\n    void add_solution(const vector<int>& seq, int score) {\n        Solution sol = make_solution(seq, score);\n\n        if (bestSol.seq.empty() || score > bestSol.score) {\n            bestSol = sol;\n        }\n\n        for (auto& e : elite) {\n            if (e.hash == sol.hash) {\n                if (sol.score > e.score) e = sol;\n                return;\n            }\n        }\n\n        elite.push_back(sol);\n        sort(elite.begin(), elite.end(), [](const Solution& a, const Solution& b) {\n            return a.score > b.score;\n        });\n        if ((int)elite.size() > 6) elite.resize(6);\n    }\n\n    const Solution& choose_parent() {\n        if (elite.empty()) return bestSol;\n        double r = rng.next_double();\n        if (elite.size() == 1) return elite[0];\n        if (r < 0.45) return elite[0];\n        if (r < 0.70) return elite[min<int>(1, elite.size() - 1)];\n        if (r < 0.88) return elite[rng.next_int(0, min<int>(2, elite.size() - 1))];\n        return elite[rng.next_int(0, (int)elite.size() - 1)];\n    }\n\n    int choose_cut(const Solution& base) {\n        int L = (int)base.seq.size() - 1;\n        if (L <= 0) return 0;\n        int maxCut = L - 1;\n        if (maxCut <= 0) return 0;\n\n        uint32_t mode = rng.next_u32() % 6;\n        int cut = 0;\n        if (mode == 0) {\n            cut = 0;\n        } else if (mode == 1) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u * u);\n        } else if (mode == 2) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u);\n        } else if (mode == 3) {\n            double u = rng.next_double();\n            cut = maxCut - (int)(maxCut * u * u);\n        } else {\n            int lo = max(0, maxCut / 3);\n            int hi = maxCut;\n            cut = rng.next_int(lo, hi);\n        }\n        if (cut < 0) cut = 0;\n        if (cut > maxCut) cut = maxCut;\n        return cut;\n    }\n\n    string seq_to_answer(const vector<int>& seq) {\n        string ans;\n        ans.reserve(max(0, (int)seq.size() - 1));\n        for (int i = 1; i < (int)seq.size(); i++) {\n            int a = seq[i - 1], b = seq[i];\n            if (b == a - N) ans.push_back('U');\n            else if (b == a + N) ans.push_back('D');\n            else if (b == a - 1) ans.push_back('L');\n            else ans.push_back('R');\n        }\n        return ans;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        bestSol = make_solution(vector<int>{start}, val[start]);\n        elite.clear();\n        elite.push_back(bestSol);\n\n        // Initial diversified restarts\n        for (int rep = 0; rep < 6 && elapsed() < 0.18; rep++) {\n            Params par = sample_params();\n            auto [seq, score] = grow_from(bestSol, 0, par);\n            add_solution(seq, score);\n        }\n\n        while (elapsed() < TL) {\n            Params par = sample_params();\n\n            bool doRestart = elite.empty() || rng.next_double() < 0.12;\n            if (doRestart) {\n                auto [seq, score] = grow_from(bestSol, 0, par);\n                add_solution(seq, score);\n                continue;\n            }\n\n            const Solution& base = choose_parent();\n            int cut = choose_cut(base);\n            auto [seq, score] = grow_from(base, cut, par);\n            add_solution(seq, score);\n        }\n\n        cout << seq_to_answer(bestSol.seq) << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horizontal;\n    int i, j;\n};\n\nstruct Sample {\n    double y = 0.0;\n    double w = 1.0;\n    array<array<unsigned char, 30>, 30> hp{};\n    array<array<unsigned char, 30>, 30> vp{};\n};\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr double PRIOR = 5000.0;\n    static constexpr double INF = 1e100;\n\n    vector<Sample> samples;\n\n    // Avg model\n    double AvgH[N], AvgV[N];\n\n    // Split model\n    int splitH[N], splitV[N];\n    double A[N], B[N];\n    double C[N], Dv[N];\n\n    // Confidence in split model\n    double splitMix = 0.0;\n\n    // Local edge estimates (stored around mixed model)\n    double edgeH[N][N - 1];\n    double edgeV[N - 1][N];\n    int cntH[N][N - 1];\n    int cntV[N - 1][N];\n\n    static double clamp_cost(double x) {\n        if (x < 1000.0) return 1000.0;\n        if (x > 9000.0) return 9000.0;\n        return x;\n    }\n\n    static double clamp01(double x) {\n        if (x < 0.0) return 0.0;\n        if (x > 1.0) return 1.0;\n        return x;\n    }\n\n    bool need_rebuild(int turn) const {\n        if (turn == 0) return true;\n        if (turn < 80) return turn % 4 == 0;\n        if (turn < 250) return turn % 8 == 0;\n        return turn % 12 == 0;\n    }\n\n    double avg_h(int i, int) const { return AvgH[i]; }\n    double avg_v(int, int j) const { return AvgV[j]; }\n\n    double split_h(int i, int j) const {\n        return (j < splitH[i] ? A[i] : B[i]);\n    }\n    double split_v(int i, int j) const {\n        return (i < splitV[j] ? C[j] : Dv[j]);\n    }\n\n    double mixed_h(int i, int j) const {\n        return clamp_cost((1.0 - splitMix) * AvgH[i] + splitMix * split_h(i, j));\n    }\n    double mixed_v(int i, int j) const {\n        return clamp_cost((1.0 - splitMix) * AvgV[j] + splitMix * split_v(i, j));\n    }\n\n    double route_h_mixed(int i, int j) const {\n        double g = mixed_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return g;\n        double alpha = (double)c / (c + 8.0);\n        return clamp_cost(g + alpha * (edgeH[i][j] - g));\n    }\n    double route_v_mixed(int i, int j) const {\n        double g = mixed_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return g;\n        double alpha = (double)c / (c + 8.0);\n        return clamp_cost(g + alpha * (edgeV[i][j] - g));\n    }\n\n    // Transfer mixed residuals to avg/split hypotheses\n    double route_h_avg(int i, int j) const {\n        double base = avg_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return base;\n        double alpha = (double)c / (c + 8.0);\n        double resid = edgeH[i][j] - mixed_h(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_v_avg(int i, int j) const {\n        double base = avg_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return base;\n        double alpha = (double)c / (c + 8.0);\n        double resid = edgeV[i][j] - mixed_v(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_h_split(int i, int j) const {\n        double base = split_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return base;\n        double alpha = (double)c / (c + 8.0);\n        double resid = edgeH[i][j] - mixed_h(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_v_split(int i, int j) const {\n        double base = split_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return base;\n        double alpha = (double)c / (c + 8.0);\n        double resid = edgeV[i][j] - mixed_v(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n\n    double prior_est_h(int i, int j) const {\n        if (cntH[i][j] == 0) return mixed_h(i, j);\n        return route_h_mixed(i, j);\n    }\n    double prior_est_v(int i, int j) const {\n        if (cntV[i][j] == 0) return mixed_v(i, j);\n        return route_v_mixed(i, j);\n    }\n\n    void fit_avg_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                AvgH[i] = PRIOR;\n                AvgV[i] = PRIOR;\n            }\n            return;\n        }\n\n        vector<double> pred(m, 0.0);\n        auto rebuild_pred = [&]() {\n            fill(pred.begin(), pred.end(), 0.0);\n            for (int n = 0; n < m; n++) {\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (int)samples[n].hp[i][29] * AvgH[i];\n                for (int j = 0; j < N; j++) s += (int)samples[n].vp[j][29] * AvgV[j];\n                pred[n] = s;\n            }\n        };\n        rebuild_pred();\n\n        double lambda = 35.0 / sqrt((double)m + 1.0) + 1.5;\n\n        for (int it = 0; it < 8; it++) {\n            for (int i = 0; i < N; i++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].hp[i][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + AvgH[i] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - AvgH[i];\n                if (fabs(delta) > 1e-12) {\n                    AvgH[i] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].hp[i][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].vp[j][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + AvgV[j] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - AvgV[j];\n                if (fabs(delta) > 1e-12) {\n                    AvgV[j] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].vp[j][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n        }\n    }\n\n    void compute_pred_split(vector<double>& pred) const {\n        int m = (int)samples.size();\n        pred.assign(m, 0.0);\n        for (int n = 0; n < m; n++) {\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)samples[n].hp[i][splitH[i]];\n                int t = (int)samples[n].hp[i][29];\n                s += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)samples[n].vp[j][splitV[j]];\n                int t = (int)samples[n].vp[j][29];\n                s += u * C[j] + (t - u) * Dv[j];\n            }\n            pred[n] = s;\n        }\n    }\n\n    void cd_update_param(double& param, vector<double>& pred, double lambda,\n                         const function<int(const Sample&)>& feat) {\n        int m = (int)samples.size();\n        double num = 0.0, den = 0.0;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f == 0.0) continue;\n            double w = samples[n].w;\n            num += w * f * (samples[n].y - pred[n] + param * f);\n            den += w * f * f;\n        }\n        double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n        double delta = nv - param;\n        if (fabs(delta) <= 1e-12) return;\n        param = nv;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f) pred[n] += delta * f;\n        }\n    }\n\n    void fit_fixed_splits(vector<double>& pred, double lambda, int iters) {\n        int m = (int)samples.size();\n        if (m == 0) return;\n        compute_pred_split(pred);\n\n        for (int it = 0; it < iters; it++) {\n            for (int i = 0; i < N; i++) {\n                int sp = splitH[i];\n                cd_update_param(A[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    return (int)s.hp[i][sp];\n                });\n                cd_update_param(B[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    int l = (int)s.hp[i][sp];\n                    int t = (int)s.hp[i][29];\n                    return t - l;\n                });\n            }\n            for (int j = 0; j < N; j++) {\n                int sp = splitV[j];\n                cd_update_param(C[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    return (int)s.vp[j][sp];\n                });\n                cd_update_param(Dv[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    int u = (int)s.vp[j][sp];\n                    int t = (int)s.vp[j][29];\n                    return t - u;\n                });\n            }\n        }\n    }\n\n    void optimize_row_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int i = 0; i < N; i++) {\n            int oldsp = splitH[i];\n            double oldA = A[i], oldB = B[i];\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int tot = (int)samples[n].hp[i][29];\n                int oldr = tot - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double tt = 0.0, tr = 0.0, rr1 = 0.0;\n            for (int n = 0; n < m; n++) {\n                double w = samples[n].w;\n                int t = (int)samples[n].hp[i][29];\n                double r = base[n];\n                tt += w * t * t;\n                tr += w * t * r;\n                rr1 += w * r * r;\n            }\n            double one = clamp_cost((tr + lambda * PRIOR) / (tt + lambda));\n            double loss1 = rr1 - 2.0 * one * tr + one * one * tt + lambda * (one - PRIOR) * (one - PRIOR);\n\n            double bestLoss = 1e300;\n            int bestSp = 15;\n            double bestA = one, bestB = one;\n            double bestLeftSup = 0.0, bestRightSup = 0.0;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n                double leftSup = 0.0, rightSup = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].hp[i][sp];\n                    int t = (int)samples[n].hp[i][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                    leftSup += w * a;\n                    rightSup += w * b;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double na = PRIOR, nb = PRIOR;\n                if (det > 1e-9) {\n                    na = (R0 * M11 - R1 * M01) / det;\n                    nb = (R1 * M00 - R0 * M01) / det;\n                }\n                na = clamp_cost(na);\n                nb = clamp_cost(nb);\n\n                double loss =\n                    rr\n                    - 2.0 * na * ar - 2.0 * nb * br\n                    + na * na * aa + 2.0 * na * nb * ab + nb * nb * bb\n                    + lambda * ((na - PRIOR) * (na - PRIOR) + (nb - PRIOR) * (nb - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestA = na;\n                    bestB = nb;\n                    bestLeftSup = leftSup;\n                    bestRightSup = rightSup;\n                }\n            }\n\n            bool useSplit = false;\n            double improve = loss1 - bestLoss;\n            if (min(bestLeftSup, bestRightSup) >= 18.0 &&\n                fabs(bestA - bestB) >= 180.0 &&\n                improve >= max(3e5, 0.0025 * loss1)) {\n                useSplit = true;\n            }\n\n            int newSp = useSplit ? bestSp : 15;\n            double newA = useSplit ? bestA : one;\n            double newB = useSplit ? bestB : one;\n\n            splitH[i] = newSp;\n            A[i] = newA;\n            B[i] = newB;\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int oldt = (int)samples[n].hp[i][29];\n                int oldr = oldt - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n\n                int newl = (int)samples[n].hp[i][newSp];\n                int newr = oldt - newl;\n                double newc = newl * newA + newr * newB;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void optimize_col_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int j = 0; j < N; j++) {\n            int oldsp = splitV[j];\n            double oldC = C[j], oldD = Dv[j];\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int tot = (int)samples[n].vp[j][29];\n                int oldd = tot - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double tt = 0.0, tr = 0.0, rr1 = 0.0;\n            for (int n = 0; n < m; n++) {\n                double w = samples[n].w;\n                int t = (int)samples[n].vp[j][29];\n                double r = base[n];\n                tt += w * t * t;\n                tr += w * t * r;\n                rr1 += w * r * r;\n            }\n            double one = clamp_cost((tr + lambda * PRIOR) / (tt + lambda));\n            double loss1 = rr1 - 2.0 * one * tr + one * one * tt + lambda * (one - PRIOR) * (one - PRIOR);\n\n            double bestLoss = 1e300;\n            int bestSp = 15;\n            double bestC = one, bestD = one;\n            double bestUpSup = 0.0, bestDownSup = 0.0;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n                double upSup = 0.0, downSup = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].vp[j][sp];\n                    int t = (int)samples[n].vp[j][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                    upSup += w * a;\n                    downSup += w * b;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double nc = PRIOR, nd = PRIOR;\n                if (det > 1e-9) {\n                    nc = (R0 * M11 - R1 * M01) / det;\n                    nd = (R1 * M00 - R0 * M01) / det;\n                }\n                nc = clamp_cost(nc);\n                nd = clamp_cost(nd);\n\n                double loss =\n                    rr\n                    - 2.0 * nc * ar - 2.0 * nd * br\n                    + nc * nc * aa + 2.0 * nc * nd * ab + nd * nd * bb\n                    + lambda * ((nc - PRIOR) * (nc - PRIOR) + (nd - PRIOR) * (nd - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestC = nc;\n                    bestD = nd;\n                    bestUpSup = upSup;\n                    bestDownSup = downSup;\n                }\n            }\n\n            bool useSplit = false;\n            double improve = loss1 - bestLoss;\n            if (min(bestUpSup, bestDownSup) >= 18.0 &&\n                fabs(bestC - bestD) >= 180.0 &&\n                improve >= max(3e5, 0.0025 * loss1)) {\n                useSplit = true;\n            }\n\n            int newSp = useSplit ? bestSp : 15;\n            double newC = useSplit ? bestC : one;\n            double newD = useSplit ? bestD : one;\n\n            splitV[j] = newSp;\n            C[j] = newC;\n            Dv[j] = newD;\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int oldt = (int)samples[n].vp[j][29];\n                int oldd = oldt - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n\n                int newu = (int)samples[n].vp[j][newSp];\n                int newd = oldt - newu;\n                double newc = newu * newC + newd * newD;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void fit_split_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = AvgH[i];\n                C[i] = Dv[i] = AvgV[i];\n            }\n            return;\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!(1000.0 <= A[i] && A[i] <= 9000.0)) A[i] = AvgH[i];\n            if (!(1000.0 <= B[i] && B[i] <= 9000.0)) B[i] = AvgH[i];\n            if (!(1000.0 <= C[i] && C[i] <= 9000.0)) C[i] = AvgV[i];\n            if (!(1000.0 <= Dv[i] && Dv[i] <= 9000.0)) Dv[i] = AvgV[i];\n            if (splitH[i] < 1 || splitH[i] > 28) splitH[i] = 15;\n            if (splitV[i] < 1 || splitV[i] > 28) splitV[i] = 15;\n        }\n\n        double lambda = 14.0 / sqrt((double)m + 1.0) + 0.9;\n        vector<double> pred;\n\n        fit_fixed_splits(pred, lambda, 4);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n        fit_fixed_splits(pred, lambda, 2);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n    }\n\n    double loss_avg_model() const {\n        double loss = 0.0;\n        for (const auto& s : samples) {\n            double pred = 0.0;\n            for (int i = 0; i < N; i++) pred += (int)s.hp[i][29] * AvgH[i];\n            for (int j = 0; j < N; j++) pred += (int)s.vp[j][29] * AvgV[j];\n            double d = pred - s.y;\n            loss += s.w * d * d;\n        }\n        return loss;\n    }\n\n    double loss_split_model() const {\n        double loss = 0.0;\n        for (const auto& s : samples) {\n            double pred = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)s.hp[i][splitH[i]];\n                int t = (int)s.hp[i][29];\n                pred += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)s.vp[j][splitV[j]];\n                int t = (int)s.vp[j][29];\n                pred += u * C[j] + (t - u) * Dv[j];\n            }\n            double d = pred - s.y;\n            loss += s.w * d * d;\n        }\n        return loss;\n    }\n\n    void recenter_local_edges() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) continue;\n                double g = mixed_h(i, j);\n                double keep = (double)cntH[i][j] / (cntH[i][j] + 4.0);\n                edgeH[i][j] = clamp_cost(g + keep * (edgeH[i][j] - g));\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) continue;\n                double g = mixed_v(i, j);\n                double keep = (double)cntV[i][j] / (cntV[i][j] + 4.0);\n                edgeV[i][j] = clamp_cost(g + keep * (edgeV[i][j] - g));\n            }\n        }\n    }\n\n    void rebuild_model() {\n        int m = (int)samples.size();\n\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                AvgH[i] = AvgV[i] = PRIOR;\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n            }\n            splitMix = 0.0;\n            return;\n        }\n\n        fit_avg_model();\n\n        if (m < 70) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = AvgH[i];\n                C[i] = Dv[i] = AvgV[i];\n            }\n            splitMix = 0.0;\n            recenter_local_edges();\n            return;\n        }\n\n        fit_split_model();\n\n        double lossAvg = loss_avg_model();\n        double lossSplit = loss_split_model();\n        double relImprove = max(0.0, lossAvg - lossSplit) / max(1.0, lossAvg);\n\n        int splitCount = 0;\n        for (int i = 0; i < N; i++) {\n            if (fabs(A[i] - B[i]) >= 1e-9) splitCount++;\n            if (fabs(C[i] - Dv[i]) >= 1e-9) splitCount++;\n        }\n        double countFactor = min(1.0, splitCount / 20.0);\n\n        double mix = (relImprove - 0.0015) / 0.0055;\n        mix = clamp01(mix);\n        mix *= (0.75 + 0.25 * countFactor);\n\n        double sampleFactor = clamp01((m - 60.0) / 160.0);\n        splitMix = mix * (0.7 + 0.3 * sampleFactor);\n\n        recenter_local_edges();\n    }\n\n    enum Mode {\n        ROUTE_AVG = 0,\n        ROUTE_MIXED = 1,\n        ROUTE_SPLIT = 2,\n        GLOBAL_AVG = 3,\n        GLOBAL_MIXED = 4,\n        GLOBAL_SPLIT = 5\n    };\n\n    double weight_h(Mode mode, int i, int j) const {\n        switch (mode) {\n            case ROUTE_AVG:    return route_h_avg(i, j);\n            case ROUTE_MIXED:  return route_h_mixed(i, j);\n            case ROUTE_SPLIT:  return route_h_split(i, j);\n            case GLOBAL_AVG:   return avg_h(i, j);\n            case GLOBAL_MIXED: return mixed_h(i, j);\n            case GLOBAL_SPLIT: return split_h(i, j);\n        }\n        return PRIOR;\n    }\n\n    double weight_v(Mode mode, int i, int j) const {\n        switch (mode) {\n            case ROUTE_AVG:    return route_v_avg(i, j);\n            case ROUTE_MIXED:  return route_v_mixed(i, j);\n            case ROUTE_SPLIT:  return route_v_split(i, j);\n            case GLOBAL_AVG:   return avg_v(i, j);\n            case GLOBAL_MIXED: return mixed_v(i, j);\n            case GLOBAL_SPLIT: return split_v(i, j);\n        }\n        return PRIOR;\n    }\n\n    string shortest_path_mode(int si, int sj, int ti, int tj, Mode mode) const {\n        const int V = N * N;\n        auto id = [&](int x, int y) { return x * N + y; };\n\n        vector<double> dist(V, INF);\n        vector<int> par(V, -1);\n        vector<char> mv(V, 0);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        int s = id(si, sj), t = id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == t) break;\n\n            int x = u / N;\n            int y = u % N;\n\n            auto relax = [&](int nx, int ny, double w, char c) {\n                int v = id(nx, ny);\n                double nd = d + w;\n                if (nd + 1e-12 < dist[v]) {\n                    dist[v] = nd;\n                    par[v] = u;\n                    mv[v] = c;\n                    pq.push({nd, v});\n                }\n            };\n\n            if (x > 0) relax(x - 1, y, weight_v(mode, x - 1, y), 'U');\n            if (x + 1 < N) relax(x + 1, y, weight_v(mode, x, y), 'D');\n            if (y > 0) relax(x, y - 1, weight_h(mode, x, y - 1), 'L');\n            if (y + 1 < N) relax(x, y + 1, weight_h(mode, x, y), 'R');\n        }\n\n        string path;\n        for (int cur = t; cur != s; cur = par[cur]) path.push_back(mv[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    struct PathEval {\n        double routeAvg = 0.0;\n        double routeMixed = 0.0;\n        double routeSplit = 0.0;\n        double globalAvg = 0.0;\n        double globalMixed = 0.0;\n        double globalSplit = 0.0;\n    };\n\n    PathEval eval_path(int si, int sj, const string& path) const {\n        PathEval pe;\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                pe.routeAvg += route_v_avg(x - 1, y);\n                pe.routeMixed += route_v_mixed(x - 1, y);\n                pe.routeSplit += route_v_split(x - 1, y);\n                pe.globalAvg += avg_v(x - 1, y);\n                pe.globalMixed += mixed_v(x - 1, y);\n                pe.globalSplit += split_v(x - 1, y);\n                --x;\n            } else if (c == 'D') {\n                pe.routeAvg += route_v_avg(x, y);\n                pe.routeMixed += route_v_mixed(x, y);\n                pe.routeSplit += route_v_split(x, y);\n                pe.globalAvg += avg_v(x, y);\n                pe.globalMixed += mixed_v(x, y);\n                pe.globalSplit += split_v(x, y);\n                ++x;\n            } else if (c == 'L') {\n                pe.routeAvg += route_h_avg(x, y - 1);\n                pe.routeMixed += route_h_mixed(x, y - 1);\n                pe.routeSplit += route_h_split(x, y - 1);\n                pe.globalAvg += avg_h(x, y - 1);\n                pe.globalMixed += mixed_h(x, y - 1);\n                pe.globalSplit += split_h(x, y - 1);\n                --y;\n            } else if (c == 'R') {\n                pe.routeAvg += route_h_avg(x, y);\n                pe.routeMixed += route_h_mixed(x, y);\n                pe.routeSplit += route_h_split(x, y);\n                pe.globalAvg += avg_h(x, y);\n                pe.globalMixed += mixed_h(x, y);\n                pe.globalSplit += split_h(x, y);\n                ++y;\n            }\n        }\n        return pe;\n    }\n\n    string choose_path(int si, int sj, int ti, int tj, int turn) const {\n        vector<string> cands;\n        cands.reserve(6);\n\n        auto add_cand = [&](const string& s) {\n            for (const string& t : cands) {\n                if (t == s) return;\n            }\n            cands.push_back(s);\n        };\n\n        add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_MIXED));\n        add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_MIXED));\n        add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_AVG));\n\n        if (splitMix <= 0.45 && turn >= 50) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_AVG));\n        }\n        if (splitMix >= 0.12) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_SPLIT));\n        }\n        if (splitMix >= 0.55 && turn >= 60) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_SPLIT));\n        }\n\n        vector<PathEval> ev(cands.size());\n        vector<double> routeScore(cands.size()), globalScore(cands.size());\n        double bestRouteMixed = INF, bestGlobalScore = INF;\n\n        double p = splitMix;\n        double stabilizer = 0.18 * (1.0 - fabs(2.0 * p - 1.0)); // more smoothing when ambiguous\n        double trustLocal = 0.18 + 0.72 * min(1.0, turn / 250.0);\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            ev[i] = eval_path(si, sj, cands[i]);\n\n            double routeHyp = (1.0 - p) * ev[i].routeAvg + p * ev[i].routeSplit;\n            double globalHyp = (1.0 - p) * ev[i].globalAvg + p * ev[i].globalSplit;\n\n            routeScore[i] = (1.0 - stabilizer) * routeHyp + stabilizer * ev[i].routeMixed;\n            globalScore[i] = (1.0 - stabilizer) * globalHyp + stabilizer * ev[i].globalMixed;\n\n            bestRouteMixed = min(bestRouteMixed, ev[i].routeMixed);\n            bestGlobalScore = min(bestGlobalScore, globalScore[i]);\n        }\n\n        int bestIdx = 0;\n        double bestScore = INF;\n        for (int i = 0; i < (int)cands.size(); i++) {\n            double score = trustLocal * routeScore[i] + (1.0 - trustLocal) * globalScore[i];\n\n            // mild guards against bad detours\n            if (ev[i].routeMixed > bestRouteMixed * 1.025 + 3500.0) {\n                score += 1e12;\n            }\n            if (globalScore[i] > bestGlobalScore * 1.018 + 2500.0) {\n                score += 5e11;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestIdx = i;\n            }\n        }\n\n        return cands[bestIdx];\n    }\n\n    void build_sample_and_edges(int si, int sj, const string& path, Sample& smp,\n                                vector<EdgeRef>& edges) const {\n        bool hused[N][N - 1] = {};\n        bool vused[N - 1][N] = {};\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                vused[x - 1][y] = true;\n                edges.push_back({false, x - 1, y});\n                --x;\n            } else if (c == 'D') {\n                vused[x][y] = true;\n                edges.push_back({false, x, y});\n                ++x;\n            } else if (c == 'L') {\n                hused[x][y - 1] = true;\n                edges.push_back({true, x, y - 1});\n                --y;\n            } else if (c == 'R') {\n                hused[x][y] = true;\n                edges.push_back({true, x, y});\n                ++y;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            smp.hp[i][0] = 0;\n            for (int j = 0; j < N - 1; j++) {\n                smp.hp[i][j + 1] = smp.hp[i][j] + (hused[i][j] ? 1 : 0);\n            }\n        }\n        for (int j = 0; j < N; j++) {\n            smp.vp[j][0] = 0;\n            for (int i = 0; i < N - 1; i++) {\n                smp.vp[j][i + 1] = smp.vp[j][i] + (vused[i][j] ? 1 : 0);\n            }\n        }\n    }\n\n    void update_local_edges(const vector<EdgeRef>& edges, double observed, int turn, double sampleWeight) {\n        if (edges.empty()) return;\n\n        vector<double> gains(edges.size());\n        double pred = 0.0, gsum = 0.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            if (e.horizontal) {\n                pred += prior_est_h(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntH[e.i][e.j] + 1.0);\n            } else {\n                pred += prior_est_v(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntV[e.i][e.j] + 1.0);\n            }\n            gsum += gains[k];\n        }\n\n        double residual = observed - pred;\n        double eta;\n        if (turn < 80) eta = 0.33;\n        else if (turn < 250) eta = 0.25;\n        else eta = 0.18;\n\n        double scale = sqrt(sampleWeight);\n        scale = max(0.75, min(1.12, scale));\n        eta *= scale;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            double delta = eta * residual * gains[k] / gsum;\n            delta = max(-800.0, min(800.0, delta));\n\n            if (e.horizontal) {\n                if (cntH[e.i][e.j] == 0) edgeH[e.i][e.j] = mixed_h(e.i, e.j);\n                edgeH[e.i][e.j] = clamp_cost(edgeH[e.i][e.j] + delta);\n\n                double g = mixed_h(e.i, e.j);\n                double cap = 2400.0;\n                edgeH[e.i][e.j] = min(edgeH[e.i][e.j], g + cap);\n                edgeH[e.i][e.j] = max(edgeH[e.i][e.j], g - cap);\n                cntH[e.i][e.j]++;\n            } else {\n                if (cntV[e.i][e.j] == 0) edgeV[e.i][e.j] = mixed_v(e.i, e.j);\n                edgeV[e.i][e.j] = clamp_cost(edgeV[e.i][e.j] + delta);\n\n                double g = mixed_v(e.i, e.j);\n                double cap = 2400.0;\n                edgeV[e.i][e.j] = min(edgeV[e.i][e.j], g + cap);\n                edgeV[e.i][e.j] = max(edgeV[e.i][e.j], g - cap);\n                cntV[e.i][e.j]++;\n            }\n        }\n    }\n\npublic:\n    Solver() {\n        for (int i = 0; i < N; i++) {\n            AvgH[i] = AvgV[i] = PRIOR;\n            splitH[i] = splitV[i] = 15;\n            A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n        }\n        splitMix = 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                edgeH[i][j] = PRIOR;\n                cntH[i][j] = 0;\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                edgeV[i][j] = PRIOR;\n                cntV[i][j] = 0;\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int turn = 0; turn < 1000; turn++) {\n            if (need_rebuild(turn)) rebuild_model();\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            string path = choose_path(si, sj, ti, tj, turn);\n\n            cout << path << '\\n';\n            cout.flush();\n\n            long long feedback;\n            cin >> feedback;\n\n            Sample smp;\n            smp.y = (double)feedback;\n\n            double base = max(50000.0, smp.y);\n            double scale = 200000.0 / base;\n            smp.w = scale * scale;\n            smp.w = max(0.35, min(3.0, smp.w));\n\n            vector<EdgeRef> edges;\n            build_sample_and_edges(si, sj, path, smp, edges);\n\n            samples.push_back(smp);\n            update_local_edges(edges, smp.y, turn, smp.w);\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAXL = 12;\nstatic constexpr int MINL = 2;\nstatic constexpr int WORDS = 13; // ceil(800/64)\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\nstatic inline int ch2v(char c) { return c - 'A'; }\nstatic inline char v2ch(int v) { return char('A' + v); }\n\nusing Bits = array<uint64_t, WORDS>;\n\ntemplate<class B>\nstatic inline bool getbit(const B& b, int i) {\n    return (b[i >> 6] >> (i & 63)) & 1ULL;\n}\ntemplate<class B>\nstatic inline void setbit(B& b, int i) {\n    b[i >> 6] |= 1ULL << (i & 63);\n}\n\nstruct Pattern {\n    int len;\n    uint64_t code;\n    int weight;\n    string s;\n};\n\nstruct ACNode {\n    array<int, 8> next{};\n    int link = 0;\n    vector<int> out;\n    ACNode() { next.fill(-1); }\n};\n\nstruct BeamState {\n    int node = 0;\n    int score = 0;\n    Bits seen{};\n    array<uint8_t, N> s{};\n};\n\nstruct Candidate {\n    array<uint8_t, N> row{};\n    Bits bits{};\n    string canon;\n};\n\nstruct MatrixState {\n    array<array<uint8_t, N>, N> a{};\n    array<Bits, N> row_bits{};\n    array<Bits, N> col_bits{};\n    vector<int> cnt;\n    int score = 0;\n};\n\nstruct Solver {\n    int M, K;\n    vector<Pattern> pats;\n    vector<int> orig_weight;\n    array<unordered_map<uint64_t, int>, MAXL + 1> id_of;\n    vector<ACNode> ac;\n\n    array<unordered_map<uint64_t, array<int, 8>>, MAXL> next_cnt;\n    array<unordered_map<uint64_t, array<int, 8>>, MAXL> prev_cnt;\n    array<int, 8> char_freq{};\n\n    mt19937_64 rng;\n    Timer timer;\n\n    Solver() : rng(chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    uint64_t encode_string(const string& s) {\n        uint64_t code = 0;\n        for (char c : s) code = (code << 3) | (uint64_t)ch2v(c);\n        return code;\n    }\n\n    string decode_string(uint64_t code, int len) {\n        string s(len, 'A');\n        for (int i = len - 1; i >= 0; --i) {\n            s[i] = v2ch((int)(code & 7ULL));\n            code >>= 3;\n        }\n        return s;\n    }\n\n    void add_pattern_to_ac(const string& s, int id) {\n        int v = 0;\n        for (char c : s) {\n            int x = ch2v(c);\n            if (ac[v].next[x] == -1) {\n                ac[v].next[x] = (int)ac.size();\n                ac.emplace_back();\n            }\n            v = ac[v].next[x];\n        }\n        ac[v].out.push_back(id);\n    }\n\n    void build_ac() {\n        ac.clear();\n        ac.emplace_back();\n        for (int id = 0; id < K; ++id) add_pattern_to_ac(pats[id].s, id);\n\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = ac[0].next[c];\n            if (u == -1) ac[0].next[c] = 0;\n            else {\n                ac[u].link = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            int lk = ac[v].link;\n            if (!ac[lk].out.empty()) {\n                auto& dst = ac[v].out;\n                auto& src = ac[lk].out;\n                dst.insert(dst.end(), src.begin(), src.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = ac[v].next[c];\n                if (u == -1) ac[v].next[c] = ac[lk].next[c];\n                else {\n                    ac[u].link = ac[lk].next[c];\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    void build_transition_stats() {\n        for (int t = 0; t < MAXL; ++t) {\n            next_cnt[t].clear();\n            prev_cnt[t].clear();\n        }\n        char_freq.fill(0);\n\n        for (const auto& p : pats) {\n            const string& s = p.s;\n            int L = p.len;\n            int w = p.weight;\n\n            for (char c : s) char_freq[ch2v(c)] += w;\n\n            for (int i = 0; i < L; ++i) {\n                uint64_t code = 0;\n                for (int t = 1; t <= 11 && i + t <= L; ++t) {\n                    code = (code << 3) | (uint64_t)ch2v(s[i + t - 1]);\n                    if (i + t < L) {\n                        auto& arr = next_cnt[t][code];\n                        arr[ch2v(s[i + t])] += w;\n                    }\n                    if (i > 0) {\n                        auto& arr = prev_cnt[t][code];\n                        arr[ch2v(s[i - 1])] += w;\n                    }\n                }\n            }\n        }\n    }\n\n    Bits compute_bits_seq(const uint8_t seq[N]) const {\n        Bits bits{};\n        bits.fill(0);\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                code = (code << 3) | (uint64_t)seq[(st + len - 1) % N];\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) setbit(bits, it->second);\n                }\n            }\n        }\n        return bits;\n    }\n\n    Bits compute_row_bits(const MatrixState& ms, int r) const {\n        uint8_t seq[N];\n        for (int c = 0; c < N; ++c) seq[c] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    Bits compute_col_bits(const MatrixState& ms, int c) const {\n        uint8_t seq[N];\n        for (int r = 0; r < N; ++r) seq[r] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    int gain_by_bits(const Bits& bits, const vector<int>& weight) const {\n        int g = 0;\n        for (int id = 0; id < K; ++id) if (getbit(bits, id)) g += weight[id];\n        return g;\n    }\n\n    int row_gain_and_bits(const array<uint8_t, N>& row, const vector<int>& weight, Bits& bits) const {\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        bits = compute_bits_seq(seq);\n        return gain_by_bits(bits, weight);\n    }\n\n    string canonical_row(const array<uint8_t, N>& row) const {\n        string best(N, 'Z');\n        for (int sh = 0; sh < N; ++sh) {\n            string cur(N, 'A');\n            for (int i = 0; i < N; ++i) cur[i] = v2ch(row[(i + sh) % N]);\n            if (cur < best) best = cur;\n        }\n        return best;\n    }\n\n    array<uint8_t, N> fallback_row(const vector<int>& weight) {\n        int best_id = -1, best_key = -1;\n        for (int i = 0; i < K; ++i) {\n            int key = weight[i] * pats[i].len;\n            if (key > best_key) best_key = key, best_id = i;\n        }\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n        if (best_id != -1) {\n            const string& s = pats[best_id].s;\n            for (int i = 0; i < (int)s.size() && i < N; ++i) row[i] = ch2v(s[i]);\n        }\n        return row;\n    }\n\n    vector<int> pick_seed_patterns(const vector<int>& weight, int topk, int randk) {\n        vector<pair<int,int>> v;\n        v.reserve(K);\n        for (int i = 0; i < K; ++i) {\n            if (weight[i] <= 0) continue;\n            int key = weight[i] * pats[i].len;\n            v.push_back({key, i});\n        }\n        sort(v.begin(), v.end(), greater<pair<int,int>>());\n\n        vector<int> res;\n        for (int i = 0; i < (int)v.size() && i < topk; ++i) res.push_back(v[i].second);\n\n        vector<int> rest;\n        for (int i = topk; i < (int)v.size(); ++i) rest.push_back(v[i].second);\n        shuffle(rest.begin(), rest.end(), rng);\n        for (int i = 0; i < (int)rest.size() && i < randk; ++i) res.push_back(rest[i]);\n        return res;\n    }\n\n    array<uint8_t, N> beam_search_row(const vector<int>& weight, const vector<uint8_t>& prefix, int BEAM = 120) {\n        if ((int)prefix.size() > N) return fallback_row(weight);\n\n        vector<BeamState> beam(1);\n        beam[0].node = 0;\n        beam[0].score = 0;\n        beam[0].seen.fill(0);\n\n        int pos = 0;\n        for (uint8_t c : prefix) {\n            beam[0].s[pos++] = c;\n            beam[0].node = ac[beam[0].node].next[c];\n            for (int id : ac[beam[0].node].out) {\n                if (weight[id] > 0 && !getbit(beam[0].seen, id)) {\n                    setbit(beam[0].seen, id);\n                    beam[0].score += weight[id];\n                }\n            }\n        }\n\n        for (int d = pos; d < N; ++d) {\n            vector<BeamState> cand;\n            cand.reserve(beam.size() * 8);\n\n            for (const auto& st : beam) {\n                for (int c = 0; c < 8; ++c) {\n                    BeamState ns = st;\n                    ns.s[d] = (uint8_t)c;\n                    ns.node = ac[st.node].next[c];\n                    for (int id : ac[ns.node].out) {\n                        if (weight[id] > 0 && !getbit(ns.seen, id)) {\n                            setbit(ns.seen, id);\n                            ns.score += weight[id];\n                        }\n                    }\n                    cand.push_back(std::move(ns));\n                }\n            }\n\n            auto cmp = [](const BeamState& a, const BeamState& b) {\n                return a.score > b.score;\n            };\n            if ((int)cand.size() > BEAM) {\n                nth_element(cand.begin(), cand.begin() + BEAM, cand.end(), cmp);\n                cand.resize(BEAM);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n            beam.swap(cand);\n        }\n\n        int best_gain = -1;\n        array<uint8_t, N> best_row{};\n        int take = min<int>(24, beam.size());\n        for (int i = 0; i < take; ++i) {\n            Bits bits{};\n            int g = row_gain_and_bits(beam[i].s, weight, bits);\n            if (g > best_gain) {\n                best_gain = g;\n                best_row = beam[i].s;\n            }\n        }\n        if (best_gain <= 0) return fallback_row(weight);\n        return best_row;\n    }\n\n    pair<int, uint8_t> best_extend_char(const deque<uint8_t>& dq, bool to_left) {\n        array<int, 8> score{};\n        for (int c = 0; c < 8; ++c) score[c] = char_freq[c] / 32;\n\n        int lim = min<int>(11, dq.size());\n        for (int t = 1; t <= lim; ++t) {\n            uint64_t code = 0;\n            if (!to_left) {\n                for (int i = (int)dq.size() - t; i < (int)dq.size(); ++i) code = (code << 3) | dq[i];\n                auto it = next_cnt[t].find(code);\n                if (it != next_cnt[t].end()) {\n                    for (int c = 0; c < 8; ++c) score[c] += it->second[c] * t * t;\n                }\n            } else {\n                for (int i = 0; i < t; ++i) code = (code << 3) | dq[i];\n                auto it = prev_cnt[t].find(code);\n                if (it != prev_cnt[t].end()) {\n                    for (int c = 0; c < 8; ++c) score[c] += it->second[c] * t * t;\n                }\n            }\n        }\n\n        int best_score = -1, best_c = 0;\n        for (int c = 0; c < 8; ++c) if (score[c] > best_score) best_score = score[c], best_c = c;\n        return {best_score, (uint8_t)best_c};\n    }\n\n    array<uint8_t, N> transition_extend_from_seed(const string& seed, int mode) {\n        deque<uint8_t> dq;\n        for (char c : seed) dq.push_back((uint8_t)ch2v(c));\n        int alt = 0;\n\n        while ((int)dq.size() < N) {\n            auto [sl, cl] = best_extend_char(dq, true);\n            auto [sr, cr] = best_extend_char(dq, false);\n\n            int side;\n            if (mode == 0) {\n                if (sl > sr) side = 0;\n                else if (sr > sl) side = 1;\n                else side = (rng() & 1);\n            } else if (mode == 1) {\n                side = 1;\n            } else if (mode == 2) {\n                side = 0;\n            } else {\n                side = (alt++ & 1);\n                if (max(sl, sr) >= 2 * min(sl, sr) + 10) side = (sl > sr ? 0 : 1);\n            }\n\n            if (side == 0) dq.push_front(cl);\n            else dq.push_back(cr);\n        }\n\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = dq[i];\n        return row;\n    }\n\n    int overlap_suffix_prefix_deque_pat(const deque<uint8_t>& dq, const string& p) const {\n        int lim = min<int>({11, (int)dq.size(), (int)p.size()});\n        for (int t = lim; t >= 1; --t) {\n            bool ok = true;\n            for (int i = 0; i < t; ++i) {\n                if (dq[(int)dq.size() - t + i] != (uint8_t)ch2v(p[i])) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return t;\n        }\n        return 0;\n    }\n\n    int overlap_suffix_prefix_pat_deque(const string& p, const deque<uint8_t>& dq) const {\n        int lim = min<int>({11, (int)dq.size(), (int)p.size()});\n        for (int t = lim; t >= 1; --t) {\n            bool ok = true;\n            for (int i = 0; i < t; ++i) {\n                if ((uint8_t)ch2v(p[(int)p.size() - t + i]) != dq[i]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return t;\n        }\n        return 0;\n    }\n\n    bool choose_best_overlap_right(const deque<uint8_t>& dq, int& best_id, int& best_ov, int& best_score) const {\n        best_id = -1;\n        best_ov = 0;\n        best_score = -1;\n        for (int id = 0; id < K; ++id) {\n            int ov = overlap_suffix_prefix_deque_pat(dq, pats[id].s);\n            if (ov <= 0 || ov >= pats[id].len) continue;\n            int sc = ov * 10000 + pats[id].weight * pats[id].len;\n            if (sc > best_score) best_score = sc, best_id = id, best_ov = ov;\n        }\n        return best_id != -1;\n    }\n\n    bool choose_best_overlap_left(const deque<uint8_t>& dq, int& best_id, int& best_ov, int& best_score) const {\n        best_id = -1;\n        best_ov = 0;\n        best_score = -1;\n        for (int id = 0; id < K; ++id) {\n            int ov = overlap_suffix_prefix_pat_deque(pats[id].s, dq);\n            if (ov <= 0 || ov >= pats[id].len) continue;\n            int sc = ov * 10000 + pats[id].weight * pats[id].len;\n            if (sc > best_score) best_score = sc, best_id = id, best_ov = ov;\n        }\n        return best_id != -1;\n    }\n\n    array<uint8_t, N> overlap_extend_from_seed(int seed_id, int mode) {\n        deque<uint8_t> dq;\n        for (char c : pats[seed_id].s) dq.push_back((uint8_t)ch2v(c));\n        int alt = 0;\n\n        while ((int)dq.size() < N) {\n            int lid, lov, lsc;\n            int rid, rov, rsc;\n            bool hasL = choose_best_overlap_left(dq, lid, lov, lsc);\n            bool hasR = choose_best_overlap_right(dq, rid, rov, rsc);\n\n            int side = 1;\n            if (mode == 0) {\n                if (!hasL && !hasR) side = (rng() & 1);\n                else if (!hasL) side = 1;\n                else if (!hasR) side = 0;\n                else if (lsc > rsc) side = 0;\n                else if (rsc > lsc) side = 1;\n                else side = (rng() & 1);\n            } else if (mode == 1) {\n                side = 1;\n                if (!hasR && hasL) side = 0;\n            } else if (mode == 2) {\n                side = 0;\n                if (!hasL && hasR) side = 1;\n            } else {\n                if (!hasL && !hasR) side = (rng() & 1);\n                else if (!hasL) side = 1;\n                else if (!hasR) side = 0;\n                else side = (alt++ & 1);\n            }\n\n            bool progressed = false;\n            if (side == 0 && hasL) {\n                const string& s = pats[lid].s;\n                for (int i = (int)s.size() - lov - 1; i >= 0 && (int)dq.size() < N; --i) {\n                    dq.push_front((uint8_t)ch2v(s[i]));\n                    progressed = true;\n                }\n            } else if (side == 1 && hasR) {\n                const string& s = pats[rid].s;\n                for (int i = rov; i < (int)s.size() && (int)dq.size() < N; ++i) {\n                    dq.push_back((uint8_t)ch2v(s[i]));\n                    progressed = true;\n                }\n            }\n\n            if (!progressed) {\n                auto [sl, cl] = best_extend_char(dq, true);\n                auto [sr, cr] = best_extend_char(dq, false);\n                if ((side == 0 && sl >= sr) || !hasR) dq.push_front(cl);\n                else dq.push_back(cr);\n            }\n        }\n\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = dq[i];\n        return row;\n    }\n\n    void add_candidate(vector<Candidate>& pool, unordered_set<string>& used, const array<uint8_t, N>& row) {\n        string canon = canonical_row(row);\n        if (!used.insert(canon).second) return;\n        Candidate c;\n        c.row = row;\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        c.bits = compute_bits_seq(seq);\n        c.canon = canon;\n        pool.push_back(std::move(c));\n    }\n\n    vector<Candidate> generate_candidate_pool() {\n        vector<Candidate> pool;\n        unordered_set<string> used;\n        used.reserve(1024);\n\n        auto generate_with_scheme = [&](vector<int> residual, int rounds, int beamw) {\n            for (int t = 0; t < rounds; ++t) {\n                if (timer.elapsed() > 0.42) return;\n\n                vector<array<uint8_t, N>> cand_rows;\n                cand_rows.push_back(beam_search_row(residual, {}, beamw));\n\n                auto seeds = pick_seed_patterns(residual, 2, 1);\n                for (int id : seeds) {\n                    vector<uint8_t> pref;\n                    for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                    cand_rows.push_back(beam_search_row(residual, pref, beamw));\n                    cand_rows.push_back(transition_extend_from_seed(pats[id].s, 0));\n                    cand_rows.push_back(overlap_extend_from_seed(id, 0));\n                }\n\n                int best_gain = -1;\n                array<uint8_t, N> best_row{};\n                Bits best_bits{};\n\n                for (auto& row : cand_rows) {\n                    Bits bits{};\n                    int g = row_gain_and_bits(row, residual, bits);\n                    if (g > best_gain) {\n                        best_gain = g;\n                        best_row = row;\n                        best_bits = bits;\n                    }\n                }\n\n                add_candidate(pool, used, best_row);\n                for (int id = 0; id < K; ++id) if (getbit(best_bits, id)) residual[id] = 0;\n            }\n        };\n\n        vector<int> w1 = orig_weight;\n        generate_with_scheme(w1, 8, 120);\n\n        vector<int> w2(K);\n        for (int i = 0; i < K; ++i) w2[i] = orig_weight[i] * pats[i].len;\n        generate_with_scheme(w2, 8, 100);\n\n        vector<int> w3(K);\n        for (int i = 0; i < K; ++i) w3[i] = pats[i].len;\n        generate_with_scheme(w3, 6, 90);\n\n        vector<pair<int,int>> heavy;\n        for (int i = 0; i < K; ++i) heavy.push_back({orig_weight[i] * pats[i].len, i});\n        sort(heavy.begin(), heavy.end(), greater<pair<int,int>>());\n\n        for (int z = 0; z < min(12, (int)heavy.size()) && timer.elapsed() <= 0.52; ++z) {\n            int id = heavy[z].second;\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 0));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 1));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 2));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 0));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 1));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 2));\n        }\n\n        if (pool.empty()) add_candidate(pool, used, fallback_row(orig_weight));\n        return pool;\n    }\n\n    vector<Candidate> generate_targeted_pool(const MatrixState& ms, double stop_time) {\n        vector<int> w(K, 0);\n        for (int id = 0; id < K; ++id) {\n            if (ms.cnt[id] == 0) w[id] = orig_weight[id] * 6;\n            else if (ms.cnt[id] == 1) w[id] = orig_weight[id] * 3;\n            else if (ms.cnt[id] == 2) w[id] = orig_weight[id];\n        }\n\n        vector<Candidate> pool;\n        unordered_set<string> used;\n        used.reserve(256);\n\n        add_candidate(pool, used, beam_search_row(w, {}, 100));\n\n        auto seeds = pick_seed_patterns(w, 8, 2);\n        for (int id : seeds) {\n            if (timer.elapsed() > stop_time) break;\n\n            vector<uint8_t> pref;\n            for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n\n            add_candidate(pool, used, beam_search_row(w, pref, 90));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 0));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 3));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 0));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 3));\n        }\n\n        if (pool.empty()) add_candidate(pool, used, fallback_row(w));\n        return pool;\n    }\n\n    vector<array<uint8_t, N>> select_rows_trial(const vector<Candidate>& pool, int mode) {\n        vector<array<uint8_t, N>> rows;\n        vector<int> residual = orig_weight;\n        vector<int> used(pool.size(), 0);\n\n        for (int it = 0; it < N; ++it) {\n            int best = -1;\n            double best_score = -1e100;\n            for (int i = 0; i < (int)pool.size(); ++i) {\n                if (used[i]) continue;\n                int g = gain_by_bits(pool[i].bits, residual);\n                double score = g;\n                if (mode == 1) score += uniform_real_distribution<double>(0.0, 3.0)(rng);\n                if (mode == 2) score += uniform_real_distribution<double>(0.0, 10.0)(rng);\n                if (mode == 3) score += uniform_real_distribution<double>(0.0, 20.0)(rng);\n                if (score > best_score) {\n                    best_score = score;\n                    best = i;\n                }\n            }\n            if (best == -1 || best_score <= 0) {\n                auto row = fallback_row(residual);\n                rows.push_back(row);\n                Bits bits{};\n                row_gain_and_bits(row, residual, bits);\n                for (int id = 0; id < K; ++id) if (getbit(bits, id)) residual[id] = 0;\n            } else {\n                used[best] = 1;\n                rows.push_back(pool[best].row);\n                for (int id = 0; id < K; ++id) if (getbit(pool[best].bits, id)) residual[id] = 0;\n            }\n        }\n        return rows;\n    }\n\n    void init_matrix_state(MatrixState& ms, const vector<array<uint8_t, N>>& rows) {\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ms.a[r][c] = rows[r][c];\n\n        for (int r = 0; r < N; ++r) ms.row_bits[r] = compute_row_bits(ms, r);\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = compute_col_bits(ms, c);\n\n        ms.cnt.assign(K, 0);\n        for (int r = 0; r < N; ++r)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.row_bits[r], id)) ms.cnt[id]++;\n\n        for (int c = 0; c < N; ++c)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.col_bits[c], id)) ms.cnt[id]++;\n\n        ms.score = 0;\n        for (int id = 0; id < K; ++id) if (ms.cnt[id] > 0) ms.score += orig_weight[id];\n    }\n\n    void transpose_state(MatrixState& ms) {\n        for (int i = 0; i < N; ++i)\n            for (int j = i + 1; j < N; ++j)\n                swap(ms.a[i][j], ms.a[j][i]);\n        swap(ms.row_bits, ms.col_bits);\n    }\n\n    int eval_row_replace(const MatrixState& ms, int r,\n                         const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                         array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) seq[i] = (i == r ? new_row[c] : ms.a[i][c]);\n            new_cols[c] = compute_bits_seq(seq);\n        }\n\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_row_replace(MatrixState& ms, int r,\n                           const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                           const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n\n        for (int c = 0; c < N; ++c) ms.a[r][c] = new_row[c];\n        ms.row_bits[r] = new_row_bits;\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = new_cols[c];\n        ms.score += delta;\n    }\n\n    bool same_exact_row(const MatrixState& ms, int r, const array<uint8_t, N>& row) const {\n        for (int c = 0; c < N; ++c) if (ms.a[r][c] != row[c]) return false;\n        return true;\n    }\n\n    bool improve_rows_from_pool(MatrixState& ms, const vector<Candidate>& pool, double time_limit) {\n        bool improved_any = false;\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int t = 0; t < N; ++t) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[t];\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            auto test_base = [&](const array<uint8_t, N>& base_row, const Bits& base_bits) {\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base_row[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, base_bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = base_bits;\n                        best_cols = new_cols;\n                    }\n                }\n            };\n\n            for (const auto& cand : pool) test_base(cand.row, cand.bits);\n            for (int i = 0; i < N; ++i) {\n                array<uint8_t, N> cur{};\n                for (int c = 0; c < N; ++c) cur[c] = ms.a[i][c];\n                test_base(cur, ms.row_bits[i]);\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved_any = true;\n            }\n        }\n        return improved_any;\n    }\n\n    bool dynamic_rebuild_rows(MatrixState& ms, double time_limit) {\n        bool improved = false;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int ii = 0; ii < N; ++ii) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[ii];\n\n            vector<int> w(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) w[id] = orig_weight[id] * 4;\n                else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) w[id] = orig_weight[id] * 2;\n            }\n\n            int sumw = 0;\n            for (int x : w) sumw += x;\n            if (sumw == 0) continue;\n\n            vector<array<uint8_t, N>> cand_rows;\n            cand_rows.push_back(beam_search_row(w, {}, 120));\n\n            auto seeds = pick_seed_patterns(w, 3, 1);\n            for (int id : seeds) {\n                vector<uint8_t> pref;\n                for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                cand_rows.push_back(beam_search_row(w, pref, 100));\n                cand_rows.push_back(transition_extend_from_seed(pats[id].s, 0));\n                cand_rows.push_back(overlap_extend_from_seed(id, 0));\n                cand_rows.push_back(overlap_extend_from_seed(id, 3));\n            }\n\n            vector<int> w2(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) w2[id] = orig_weight[id];\n                else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) w2[id] = orig_weight[id];\n            }\n            cand_rows.push_back(beam_search_row(w2, {}, 90));\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            for (auto& base : cand_rows) {\n                Bits bits{};\n                uint8_t seq[N];\n                for (int c = 0; c < N; ++c) seq[c] = base[c];\n                bits = compute_bits_seq(seq);\n\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = bits;\n                        best_cols = new_cols;\n                    }\n                }\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    int delta_replace_cols(const MatrixState& ms, const array<Bits, N>& new_cols) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n        }\n        return delta;\n    }\n\n    void apply_replace_cols(MatrixState& ms, const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n        ms.col_bits = new_cols;\n        ms.score += delta;\n    }\n\n    int delta_replace_rows(const MatrixState& ms, const array<Bits, N>& new_rows) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            if ((before == 0) != (after == 0)) delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n        }\n        return delta;\n    }\n\n    void apply_replace_rows(MatrixState& ms, const array<Bits, N>& new_rows, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            ms.cnt[id] = after;\n        }\n        ms.row_bits = new_rows;\n        ms.score += delta;\n    }\n\n    int eval_row_rotate(const MatrixState& ms, int r, int sh, array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) seq[i] = (i == r ? ms.a[r][(c + sh) % N] : ms.a[i][c]);\n            new_cols[c] = compute_bits_seq(seq);\n        }\n        return delta_replace_cols(ms, new_cols);\n    }\n\n    void apply_row_rotate(MatrixState& ms, int r, int sh, const array<Bits, N>& new_cols, int delta) {\n        array<uint8_t, N> old = ms.a[r], nw{};\n        for (int c = 0; c < N; ++c) nw[c] = old[(c + sh) % N];\n        ms.a[r] = nw;\n        apply_replace_cols(ms, new_cols, delta);\n    }\n\n    int eval_row_swap(const MatrixState& ms, int r1, int r2, array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                if (i == r1) seq[i] = ms.a[r2][c];\n                else if (i == r2) seq[i] = ms.a[r1][c];\n                else seq[i] = ms.a[i][c];\n            }\n            new_cols[c] = compute_bits_seq(seq);\n        }\n        return delta_replace_cols(ms, new_cols);\n    }\n\n    void apply_row_swap(MatrixState& ms, int r1, int r2, const array<Bits, N>& new_cols, int delta) {\n        swap(ms.a[r1], ms.a[r2]);\n        swap(ms.row_bits[r1], ms.row_bits[r2]);\n        apply_replace_cols(ms, new_cols, delta);\n    }\n\n    int eval_col_rotate(const MatrixState& ms, int c, int sh, array<Bits, N>& new_rows) const {\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) seq[j] = (j == c ? ms.a[(r + sh) % N][c] : ms.a[r][j]);\n            new_rows[r] = compute_bits_seq(seq);\n        }\n        return delta_replace_rows(ms, new_rows);\n    }\n\n    void apply_col_rotate(MatrixState& ms, int c, int sh, const array<Bits, N>& new_rows, int delta) {\n        array<uint8_t, N> old{};\n        for (int r = 0; r < N; ++r) old[r] = ms.a[r][c];\n        for (int r = 0; r < N; ++r) ms.a[r][c] = old[(r + sh) % N];\n        apply_replace_rows(ms, new_rows, delta);\n    }\n\n    int eval_col_swap(const MatrixState& ms, int c1, int c2, array<Bits, N>& new_rows) const {\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                if (j == c1) seq[j] = ms.a[r][c2];\n                else if (j == c2) seq[j] = ms.a[r][c1];\n                else seq[j] = ms.a[r][j];\n            }\n            new_rows[r] = compute_bits_seq(seq);\n        }\n        return delta_replace_rows(ms, new_rows);\n    }\n\n    void apply_col_swap(MatrixState& ms, int c1, int c2, const array<Bits, N>& new_rows, int delta) {\n        for (int r = 0; r < N; ++r) swap(ms.a[r][c1], ms.a[r][c2]);\n        swap(ms.col_bits[c1], ms.col_bits[c2]);\n        apply_replace_rows(ms, new_rows, delta);\n    }\n\n    void symmetry_hill_climb(MatrixState& ms, double time_limit) {\n        while (timer.elapsed() < time_limit) {\n            int best_delta = 0;\n            int best_type = -1, best_a = -1, best_b = -1;\n            array<Bits, N> best_lines{};\n\n            for (int r = 0; r < N; ++r) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_rotate(ms, r, sh, new_cols);\n                    if (delta > best_delta) best_delta = delta, best_type = 0, best_a = r, best_b = sh, best_lines = new_cols;\n                }\n            }\n            for (int r1 = 0; r1 < N; ++r1) {\n                for (int r2 = r1 + 1; r2 < N; ++r2) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_swap(ms, r1, r2, new_cols);\n                    if (delta > best_delta) best_delta = delta, best_type = 1, best_a = r1, best_b = r2, best_lines = new_cols;\n                }\n            }\n            for (int c = 0; c < N; ++c) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_rotate(ms, c, sh, new_rows);\n                    if (delta > best_delta) best_delta = delta, best_type = 2, best_a = c, best_b = sh, best_lines = new_rows;\n                }\n            }\n            for (int c1 = 0; c1 < N; ++c1) {\n                for (int c2 = c1 + 1; c2 < N; ++c2) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_swap(ms, c1, c2, new_rows);\n                    if (delta > best_delta) best_delta = delta, best_type = 3, best_a = c1, best_b = c2, best_lines = new_rows;\n                }\n            }\n\n            if (best_delta <= 0) break;\n            if (best_type == 0) apply_row_rotate(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 1) apply_row_swap(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 2) apply_col_rotate(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 3) apply_col_swap(ms, best_a, best_b, best_lines, best_delta);\n        }\n    }\n\n    int calc_delta_two(const MatrixState& ms, const Bits& old1, const Bits& new1,\n                       const Bits& old2, const Bits& new2) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before - (int)getbit(old1, id) - (int)getbit(old2, id)\n                               + (int)getbit(new1, id) + (int)getbit(new2, id);\n            if ((before == 0) != (after == 0)) delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n        }\n        return delta;\n    }\n\n    void apply_two(MatrixState& ms, const Bits& old1, const Bits& new1,\n                   const Bits& old2, const Bits& new2) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(old1, id);\n            after -= (int)getbit(old2, id);\n            after += (int)getbit(new1, id);\n            after += (int)getbit(new2, id);\n            ms.cnt[id] = after;\n        }\n    }\n\n    void cell_local_search(MatrixState& ms, double time_limit) {\n        uniform_real_distribution<double> urd(0.0, 1.0);\n        auto bestA = ms.a;\n        int bestScore = ms.score;\n\n        while (timer.elapsed() < time_limit) {\n            double prog = timer.elapsed() / time_limit;\n            double T = 1.2 * pow(0.02 / 1.2, prog);\n\n            int r = (int)(rng() % N);\n            int c = (int)(rng() % N);\n            uint8_t oldch = ms.a[r][c];\n\n            Bits oldR = ms.row_bits[r];\n            Bits oldC = ms.col_bits[c];\n\n            int best_delta = -1000000000;\n            uint8_t best_ch = oldch;\n            Bits bestR = oldR, bestC = oldC;\n\n            for (uint8_t ch = 0; ch < 8; ++ch) {\n                if (ch == oldch) continue;\n                ms.a[r][c] = ch;\n                Bits newR = compute_row_bits(ms, r);\n                Bits newC = compute_col_bits(ms, c);\n                int delta = calc_delta_two(ms, oldR, newR, oldC, newC);\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_ch = ch;\n                    bestR = newR;\n                    bestC = newC;\n                }\n            }\n\n            bool accept = false;\n            if (best_delta >= 0) accept = true;\n            else if (urd(rng) < exp((double)best_delta / T)) accept = true;\n\n            if (accept && best_ch != oldch) {\n                ms.a[r][c] = best_ch;\n                apply_two(ms, oldR, bestR, oldC, bestC);\n                ms.row_bits[r] = bestR;\n                ms.col_bits[c] = bestC;\n                ms.score += best_delta;\n                if (ms.score > bestScore) bestScore = ms.score, bestA = ms.a;\n            } else {\n                ms.a[r][c] = oldch;\n            }\n        }\n\n        ms.a = bestA;\n    }\n\n    vector<string> solve() {\n        int n;\n        cin >> n >> M;\n\n        array<unordered_map<uint64_t, int>, MAXL + 1> cnt_of;\n        for (int len = MINL; len <= MAXL; ++len) cnt_of[len].reserve(M * 2);\n\n        for (int i = 0; i < M; ++i) {\n            string s;\n            cin >> s;\n            cnt_of[(int)s.size()][encode_string(s)]++;\n        }\n\n        pats.clear();\n        for (int len = MINL; len <= MAXL; ++len) {\n            id_of[len].clear();\n            id_of[len].reserve(cnt_of[len].size() * 2 + 1);\n            for (auto& kv : cnt_of[len]) {\n                Pattern p;\n                p.len = len;\n                p.code = kv.first;\n                p.weight = kv.second;\n                p.s = decode_string(kv.first, len);\n                int id = (int)pats.size();\n                pats.push_back(std::move(p));\n                id_of[len][kv.first] = id;\n            }\n        }\n\n        K = (int)pats.size();\n        orig_weight.assign(K, 0);\n        for (int i = 0; i < K; ++i) orig_weight[i] = pats[i].weight;\n\n        build_ac();\n        build_transition_stats();\n\n        auto pool = generate_candidate_pool();\n\n        MatrixState best_ms;\n        int best_init_score = -1;\n        for (int trial = 0; trial < 4; ++trial) {\n            auto rows = select_rows_trial(pool, trial);\n            MatrixState ms;\n            init_matrix_state(ms, rows);\n            if (ms.score > best_init_score) {\n                best_init_score = ms.score;\n                best_ms = ms;\n            }\n        }\n\n        MatrixState ms = best_ms;\n\n        if (timer.elapsed() < 0.95) improve_rows_from_pool(ms, pool, 0.95);\n        if (timer.elapsed() < 1.40) dynamic_rebuild_rows(ms, 1.40);\n\n        if (timer.elapsed() < 1.75) {\n            transpose_state(ms);\n            improve_rows_from_pool(ms, pool, 1.75);\n        }\n        if (timer.elapsed() < 2.00) {\n            dynamic_rebuild_rows(ms, 2.00);\n            transpose_state(ms);\n        } else {\n            transpose_state(ms);\n        }\n\n        if (timer.elapsed() < 2.22) {\n            auto tpool = generate_targeted_pool(ms, 2.16);\n            improve_rows_from_pool(ms, tpool, 2.22);\n        }\n\n        if (timer.elapsed() < 2.42) {\n            transpose_state(ms);\n            auto tpool2 = generate_targeted_pool(ms, 2.36);\n            improve_rows_from_pool(ms, tpool2, 2.42);\n            transpose_state(ms);\n        }\n\n        if (timer.elapsed() < 2.72) symmetry_hill_climb(ms, 2.72);\n        if (timer.elapsed() < 2.88) dynamic_rebuild_rows(ms, 2.88);\n        if (timer.elapsed() < 2.95 && ms.score < M) cell_local_search(ms, 2.95);\n\n        vector<string> ans(N, string(N, 'A'));\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ans[r][c] = v2ch(ms.a[r][c]);\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    auto ans = solver.solve();\n    for (auto& s : ans) cout << s << '\\n';\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\n\nstruct Dinic {\n    struct Edge {\n        int to, rev;\n        ll cap;\n    };\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic() {}\n    Dinic(int n) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, ll 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\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();\n            q.pop();\n            for (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\n    ll dfs(int v, int t, ll 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[v] >= level[e.to]) continue;\n            ll d = dfs(e.to, t, min(f, e.cap));\n            if (d <= 0) continue;\n            e.cap -= d;\n            g[e.to][e.rev].cap += d;\n            return d;\n        }\n        return 0;\n    }\n\n    ll maxflow(int s, int t) {\n        ll flow = 0;\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n            while (true) {\n                ll f = dfs(s, t, INF64);\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n\n    vector<char> reachable_from(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();\n            q.pop();\n            for (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 MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow() {}\n    MinCostFlow(int n) : n(n), g(n) {}\n\n    int add_edge(int fr, int to, int cap, ll cost) {\n        int idx = (int)g[fr].size();\n        g[fr].push_back({to, (int)g[to].size(), cap, cost});\n        g[to].push_back({fr, idx, 0, -cost});\n        return idx;\n    }\n\n    // augment only while s-t shortest path has negative total cost\n    ll min_cost_negative_paths(int s, int t) {\n        ll total = 0;\n        while (true) {\n            vector<ll> dist(n, INF64);\n            vector<int> pv(n, -1), pe(n, -1);\n            vector<char> inq(n, 0);\n            queue<int> q;\n            dist[s] = 0;\n            q.push(s);\n            inq[s] = 1;\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                inq[v] = 0;\n                for (int i = 0; i < (int)g[v].size(); i++) {\n                    auto &e = g[v][i];\n                    if (e.cap <= 0) continue;\n                    ll nd = dist[v] + e.cost;\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        if (!inq[e.to]) {\n                            inq[e.to] = 1;\n                            q.push(e.to);\n                        }\n                    }\n                }\n            }\n            if (dist[t] == INF64 || dist[t] >= 0) break;\n            int f = 1;\n            for (int v = t; v != s; v = pv[v]) {\n                auto &e = g[pv[v]][pe[v]];\n                f = min(f, e.cap);\n            }\n            for (int v = t; v != s; v = pv[v]) {\n                auto &e = g[pv[v]][pe[v]];\n                e.cap -= f;\n                g[v][e.rev].cap += f;\n            }\n            total += dist[t] * f;\n        }\n        return total;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    cin >> N >> si >> sj;\n    vector<string> c(N);\n    for (int i = 0; i < N; i++) cin >> c[i];\n\n    vector<vector<int>> cellId(N, vector<int>(N, -1));\n    vector<int> rr, cc, enterCost;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (c[i][j] != '#') {\n                cellId[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                enterCost.push_back(c[i][j] - '0');\n            }\n        }\n    }\n    int M = (int)rr.size();\n    int startCell = cellId[si][sj];\n\n    vector<vector<int>> nbr(M);\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (0 <= ni && ni < N && 0 <= nj && nj < N && cellId[ni][nj] != -1) {\n                nbr[id].push_back(cellId[ni][nj]);\n            }\n        }\n    }\n\n    auto dijkstra = [&](int src, bool reverse, bool needPrev) {\n        vector<ll> dist(M, INF64);\n        vector<int> prev(needPrev ? M : 0, -1);\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n        while (!pq.empty()) {\n            auto [cd, u] = pq.top();\n            pq.pop();\n            if (cd != dist[u]) continue;\n            for (int v : nbr[u]) {\n                ll w = reverse ? enterCost[u] : enterCost[v];\n                ll nd = cd + w;\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (needPrev) prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n        return pair<vector<ll>, vector<int>>(move(dist), move(prev));\n    };\n\n    auto [distFromStart, _d0] = dijkstra(startCell, false, false);\n    auto [distToStart, _d1] = dijkstra(startCell, true, false);\n\n    vector<vector<int>> hSeg(N, vector<int>(N, -1));\n    vector<vector<int>> vSeg(N, vector<int>(N, -1));\n    int Hcnt = 0, Vcnt = 0;\n\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (c[i][j] == '#') {\n                j++;\n                continue;\n            }\n            int k = j;\n            while (k < N && c[i][k] != '#') {\n                hSeg[i][k] = Hcnt;\n                k++;\n            }\n            Hcnt++;\n            j = k;\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (c[i][j] == '#') {\n                i++;\n                continue;\n            }\n            int k = i;\n            while (k < N && c[k][j] != '#') {\n                vSeg[k][j] = Vcnt;\n                k++;\n            }\n            Vcnt++;\n            i = k;\n        }\n    }\n\n    vector<int> cellH(M), cellV(M);\n    vector<vector<int>> cellsOfH(Hcnt), cellsOfV(Vcnt);\n    vector<vector<int>> adjV(Hcnt);\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        int h = hSeg[i][j];\n        int v = vSeg[i][j];\n        cellH[id] = h;\n        cellV[id] = v;\n        cellsOfH[h].push_back(id);\n        cellsOfV[v].push_back(id);\n        adjV[h].push_back(v);\n    }\n\n    int startH = cellH[startCell];\n    int startV = cellV[startCell];\n\n    auto cellRoundTrip = [&](int id) -> ll {\n        return distFromStart[id] + distToStart[id];\n    };\n\n    // weighted minimum vertex cover on segment bipartite graph\n    vector<ll> wH(Hcnt, INF64), wV(Vcnt, INF64);\n    for (int id = 0; id < M; id++) {\n        ll w = cellRoundTrip(id);\n        wH[cellH[id]] = min(wH[cellH[id]], w);\n        wV[cellV[id]] = min(wV[cellV[id]], w);\n    }\n    wH[startH] = 0;\n    wV[startV] = 0;\n\n    vector<char> selH(Hcnt, 0), selV(Vcnt, 0);\n    {\n        int S = Hcnt + Vcnt;\n        int T = S + 1;\n        Dinic mf(Hcnt + Vcnt + 2);\n        ll sumW = 0;\n        for (int h = 0; h < Hcnt; h++) {\n            mf.add_edge(S, h, wH[h]);\n            sumW += wH[h];\n        }\n        for (int v = 0; v < Vcnt; v++) {\n            mf.add_edge(Hcnt + v, T, wV[v]);\n            sumW += wV[v];\n        }\n        ll BIG = max<ll>((ll)1e15, sumW + 1);\n        for (int h = 0; h < Hcnt; h++) {\n            for (int v : adjV[h]) mf.add_edge(h, Hcnt + v, BIG);\n        }\n        mf.maxflow(S, T);\n        vector<char> reach = mf.reachable_from(S);\n        for (int h = 0; h < Hcnt; h++) selH[h] = !reach[h];\n        for (int v = 0; v < Vcnt; v++) selV[v] = reach[Hcnt + v];\n    }\n\n    vector<char> needH = selH, needV = selV;\n    needH[startH] = 0;\n    needV[startV] = 0;\n\n    // matching-based watch-cell selection\n    vector<char> chosenCell(M, 0);\n    vector<int> mapH(Hcnt, -1), revH;\n    vector<int> mapV(Vcnt, -1), revV;\n    for (int h = 0; h < Hcnt; h++) if (needH[h]) {\n        mapH[h] = (int)revH.size();\n        revH.push_back(h);\n    }\n    for (int v = 0; v < Vcnt; v++) if (needV[v]) {\n        mapV[v] = (int)revV.size();\n        revV.push_back(v);\n    }\n\n    int nH = (int)revH.size();\n    int nV = (int)revV.size();\n\n    vector<ll> bestSingleHCost(Hcnt, INF64), bestSingleVCost(Vcnt, INF64);\n    vector<int> bestSingleHCell(Hcnt, -1), bestSingleVCell(Vcnt, -1);\n\n    for (int h : revH) {\n        for (int id : cellsOfH[h]) {\n            ll w = cellRoundTrip(id);\n            if (w < bestSingleHCost[h]) {\n                bestSingleHCost[h] = w;\n                bestSingleHCell[h] = id;\n            }\n        }\n    }\n    for (int v : revV) {\n        for (int id : cellsOfV[v]) {\n            ll w = cellRoundTrip(id);\n            if (w < bestSingleVCost[v]) {\n                bestSingleVCost[v] = w;\n                bestSingleVCell[v] = id;\n            }\n        }\n    }\n\n    struct PairEdgeInfo {\n        int hnode;\n        int edgeIdx;\n        int ih, iv;\n        int cell;\n    };\n    vector<PairEdgeInfo> pairEdges;\n\n    if (nH > 0 && nV > 0) {\n        int S = 0;\n        int hBase = 1;\n        int vBase = hBase + nH;\n        int T = vBase + nV;\n        MinCostFlow mcf(T + 1);\n\n        for (int ih = 0; ih < nH; ih++) mcf.add_edge(S, hBase + ih, 1, 0);\n        for (int iv = 0; iv < nV; iv++) mcf.add_edge(vBase + iv, T, 1, 0);\n\n        for (int id = 0; id < M; id++) {\n            int h = cellH[id], v = cellV[id];\n            int ih = mapH[h], iv = mapV[v];\n            if (ih == -1 || iv == -1) continue;\n            ll saving = bestSingleHCost[h] + bestSingleVCost[v] - cellRoundTrip(id);\n            if (saving <= 0) continue;\n            int hnode = hBase + ih;\n            int vnode = vBase + iv;\n            int eidx = mcf.add_edge(hnode, vnode, 1, -saving);\n            pairEdges.push_back({hnode, eidx, ih, iv, id});\n        }\n\n        mcf.min_cost_negative_paths(S, T);\n\n        vector<char> matchedH(nH, 0), matchedV(nV, 0);\n        for (auto &pe : pairEdges) {\n            auto &e = mcf.g[pe.hnode][pe.edgeIdx];\n            if (e.cap == 0) {\n                chosenCell[pe.cell] = 1;\n                matchedH[pe.ih] = 1;\n                matchedV[pe.iv] = 1;\n            }\n        }\n\n        for (int ih = 0; ih < nH; ih++) if (!matchedH[ih]) {\n            int h = revH[ih];\n            if (bestSingleHCell[h] != -1) chosenCell[bestSingleHCell[h]] = 1;\n        }\n        for (int iv = 0; iv < nV; iv++) if (!matchedV[iv]) {\n            int v = revV[iv];\n            if (bestSingleVCell[v] != -1) chosenCell[bestSingleVCell[v]] = 1;\n        }\n    }\n\n    // remove redundant explicit watch cells\n    vector<int> chosenList;\n    for (int id = 0; id < M; id++) if (chosenCell[id]) chosenList.push_back(id);\n\n    vector<int> cntSelH(Hcnt, 0), cntSelV(Vcnt, 0);\n    if (selH[startH]) cntSelH[startH]++;\n    if (selV[startV]) cntSelV[startV]++;\n    for (int id : chosenList) {\n        if (selH[cellH[id]]) cntSelH[cellH[id]]++;\n        if (selV[cellV[id]]) cntSelV[cellV[id]]++;\n    }\n\n    sort(chosenList.begin(), chosenList.end(), [&](int a, int b) {\n        ll wa = cellRoundTrip(a), wb = cellRoundTrip(b);\n        if (wa != wb) return wa > wb;\n        if (rr[a] != rr[b]) return rr[a] < rr[b];\n        return cc[a] < cc[b];\n    });\n\n    for (int id : chosenList) {\n        if (!chosenCell[id]) continue;\n        int h = cellH[id], v = cellV[id];\n        bool ok = true;\n        if (selH[h] && cntSelH[h] <= 1) ok = false;\n        if (selV[v] && cntSelV[v] <= 1) ok = false;\n        if (ok) {\n            chosenCell[id] = 0;\n            if (selH[h]) cntSelH[h]--;\n            if (selV[v]) cntSelV[v]--;\n        }\n    }\n\n    vector<int> relCells;\n    relCells.push_back(startCell);\n    for (int id = 0; id < M; id++) {\n        if (chosenCell[id] && id != startCell) relCells.push_back(id);\n    }\n    int R = (int)relCells.size();\n\n    vector<vector<ll>> distMat(R, vector<ll>(R, INF64));\n    vector<vector<int>> prevs(R, vector<int>(M, -1));\n    for (int s = 0; s < R; s++) {\n        auto [dist, prev] = dijkstra(relCells[s], false, true);\n        prevs[s] = move(prev);\n        for (int t = 0; t < R; t++) distMat[s][t] = dist[relCells[t]];\n    }\n\n    auto cycleCost = [&](const vector<int>& cyc) -> ll {\n        ll ret = 0;\n        int sz = (int)cyc.size();\n        for (int i = 0; i < sz; i++) ret += distMat[cyc[i]][cyc[(i + 1) % sz]];\n        return ret;\n    };\n\n    // arc coverage between waypoint pairs\n    int RR = R;\n    vector<vector<int>> arcHs(RR * RR), arcVs(RR * RR);\n    vector<int> seenH(Hcnt, -1), seenV(Vcnt, -1);\n    int stamp = 0;\n\n    auto build_arc_coverage = [&](int s, int t) {\n        int idx = s * RR + t;\n        stamp++;\n\n        vector<int> pathCells;\n        int srcCell = relCells[s];\n        int dstCell = relCells[t];\n        pathCells.push_back(srcCell);\n        if (srcCell != dstCell) {\n            vector<int> rev;\n            int cur = dstCell;\n            while (cur != srcCell) {\n                int p = prevs[s][cur];\n                if (p == -1) break;\n                rev.push_back(cur);\n                cur = p;\n            }\n            reverse(rev.begin(), rev.end());\n            for (int x : rev) pathCells.push_back(x);\n        }\n\n        auto &hs = arcHs[idx];\n        auto &vs = arcVs[idx];\n        hs.clear();\n        vs.clear();\n\n        for (int cell : pathCells) {\n            int h = cellH[cell], v = cellV[cell];\n            if (seenH[h] != stamp) {\n                seenH[h] = stamp;\n                hs.push_back(h);\n            }\n            if (seenV[v] != stamp) {\n                seenV[v] = stamp;\n                vs.push_back(v);\n            }\n        }\n    };\n\n    for (int s = 0; s < RR; s++) {\n        for (int t = 0; t < RR; t++) build_arc_coverage(s, t);\n    }\n\n    auto add_arc_cov = [&](vector<int>& cntH2, vector<int>& cntV2, int a, int b, int delta) {\n        int idx = a * RR + b;\n        for (int h : arcHs[idx]) cntH2[h] += delta;\n        for (int v : arcVs[idx]) cntV2[v] += delta;\n    };\n\n    auto full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2) -> bool {\n        for (int id = 0; id < M; id++) {\n            if (cntH2[cellH[id]] == 0 && cntV2[cellV[id]] == 0) return false;\n        }\n        return true;\n    };\n\n    auto cycle_is_covered = [&](const vector<int>& cyc) -> bool {\n        vector<int> cntH2(Hcnt, 0), cntV2(Vcnt, 0);\n        int sz = (int)cyc.size();\n        for (int i = 0; i < sz; i++) {\n            add_arc_cov(cntH2, cntV2, cyc[i], cyc[(i + 1) % sz], +1);\n        }\n        return full_covered(cntH2, cntV2);\n    };\n\n    auto build_initial_cheapest_insertion = [&]() -> vector<int> {\n        if (R == 1) return vector<int>{0};\n        vector<int> cyc;\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestInit = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll val = distMat[0][i] + distMat[i][0];\n            if (val < bestInit) {\n                bestInit = val;\n                first = i;\n            }\n        }\n        cyc = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            ll bestDelta = INF64;\n            int bestNode = -1, bestPos = -1;\n            int sz = (int)cyc.size();\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                for (int pos = 0; pos < sz; pos++) {\n                    int a = cyc[pos];\n                    int b = cyc[(pos + 1) % sz];\n                    ll delta = distMat[a][x] + distMat[x][b] - distMat[a][b];\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestNode = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            used[bestNode] = 1;\n            cyc.insert(cyc.begin() + bestPos + 1, bestNode);\n        }\n        return cyc;\n    };\n\n    auto build_initial_nearest_neighbor = [&]() -> vector<int> {\n        vector<int> cyc = {0};\n        if (R == 1) return cyc;\n        vector<char> used(R, 0);\n        used[0] = 1;\n        int cur = 0;\n        for (int step = 1; step < R; step++) {\n            int best = -1;\n            ll bestVal = INF64;\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                ll val = distMat[cur][x];\n                if (val < bestVal) {\n                    bestVal = val;\n                    best = x;\n                }\n            }\n            used[best] = 1;\n            cyc.push_back(best);\n            cur = best;\n        }\n        return cyc;\n    };\n\n    auto build_initial_farthest_insertion = [&]() -> vector<int> {\n        if (R == 1) return vector<int>{0};\n        vector<int> cyc;\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestFar = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll val = distMat[0][i] + distMat[i][0];\n            if (val > bestFar) {\n                bestFar = val;\n                first = i;\n            }\n        }\n        cyc = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            int choose = -1;\n            ll chooseScore = -1;\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                ll mind = INF64;\n                for (int u : cyc) {\n                    mind = min(mind, distMat[u][x] + distMat[x][u]);\n                }\n                if (mind > chooseScore) {\n                    chooseScore = mind;\n                    choose = x;\n                }\n            }\n\n            int bestPos = -1;\n            ll bestDelta = INF64;\n            int sz = (int)cyc.size();\n            for (int pos = 0; pos < sz; pos++) {\n                int a = cyc[pos];\n                int b = cyc[(pos + 1) % sz];\n                ll delta = distMat[a][choose] + distMat[choose][b] - distMat[a][b];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n            used[choose] = 1;\n            cyc.insert(cyc.begin() + bestPos + 1, choose);\n        }\n        return cyc;\n    };\n\n    auto build_initial_angle = [&](bool rev) -> vector<int> {\n        vector<pair<pair<double, ll>, int>> ord;\n        for (int i = 1; i < R; i++) {\n            int cell = relCells[i];\n            double ang = atan2((double)rr[cell] - si, (double)cc[cell] - sj);\n            ll rad = 1LL * (rr[cell] - si) * (rr[cell] - si) + 1LL * (cc[cell] - sj) * (cc[cell] - sj);\n            ord.push_back({{ang, rad}, i});\n        }\n        sort(ord.begin(), ord.end(), [&](auto &a, auto &b) {\n            if (a.first.first != b.first.first) return a.first.first < b.first.first;\n            return a.first.second < b.first.second;\n        });\n        vector<int> cyc = {0};\n        if (rev) {\n            for (int i = (int)ord.size() - 1; i >= 0; i--) cyc.push_back(ord[i].second);\n        } else {\n            for (auto &e : ord) cyc.push_back(e.second);\n        }\n        return cyc;\n    };\n\n    auto pre_local_search = [&](vector<int>& cyc) {\n        if ((int)cyc.size() <= 2) return;\n        for (int phase = 0; phase < 3; phase++) {\n            bool improved = true;\n            while (improved) {\n                improved = false;\n                int sz = (int)cyc.size();\n\n                // Or-opt len 1..3\n                for (int len = 1; len <= 3 && !improved; len++) {\n                    if (len >= sz) break;\n                    for (int i = 1; i + len - 1 < sz && !improved; i++) {\n                        int k = i + len - 1;\n                        int a = cyc[i - 1];\n                        int x1 = cyc[i];\n                        int xk = cyc[k];\n                        int b = cyc[(k + 1) % sz];\n\n                        for (int j = 0; j < sz && !improved; j++) {\n                            if (j >= i - 1 && j <= k) continue;\n                            int c1 = cyc[j];\n                            int d1 = cyc[(j + 1) % sz];\n\n                            ll delta =\n                                distMat[a][b] + distMat[c1][x1] + distMat[xk][d1]\n                                - distMat[a][x1] - distMat[xk][b] - distMat[c1][d1];\n\n                            if (delta < 0) {\n                                vector<int> block(cyc.begin() + i, cyc.begin() + k + 1);\n                                cyc.erase(cyc.begin() + i, cyc.begin() + k + 1);\n                                int pos;\n                                if (j < i) pos = j + 1;\n                                else pos = j - len + 1;\n                                cyc.insert(cyc.begin() + pos, block.begin(), block.end());\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n                if (improved) continue;\n\n                // Swap\n                sz = (int)cyc.size();\n                ll curCost = cycleCost(cyc);\n                for (int i = 1; i < sz && !improved; i++) {\n                    for (int j = i + 1; j < sz && !improved; j++) {\n                        vector<int> nc = cyc;\n                        swap(nc[i], nc[j]);\n                        ll ncCost = cycleCost(nc);\n                        if (ncCost < curCost) {\n                            cyc.swap(nc);\n                            curCost = ncCost;\n                            improved = true;\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    auto delete_waypoints = [&](vector<int>& cyc) {\n        vector<int> covH(Hcnt, 0), covV(Vcnt, 0);\n        int sz = (int)cyc.size();\n        for (int i = 0; i < sz; i++) {\n            add_arc_cov(covH, covV, cyc[i], cyc[(i + 1) % sz], +1);\n        }\n\n        while ((int)cyc.size() > 1) {\n            sz = (int)cyc.size();\n            int bestPos = -1;\n            ll bestDelta = 0;\n\n            for (int pos = 1; pos < sz; pos++) {\n                int a = cyc[(pos - 1 + sz) % sz];\n                int b = cyc[pos];\n                int c2 = cyc[(pos + 1) % sz];\n                ll delta = distMat[a][c2] - distMat[a][b] - distMat[b][c2];\n\n                add_arc_cov(covH, covV, a, b, -1);\n                add_arc_cov(covH, covV, b, c2, -1);\n                add_arc_cov(covH, covV, a, c2, +1);\n\n                bool ok = full_covered(covH, covV);\n\n                add_arc_cov(covH, covV, a, c2, -1);\n                add_arc_cov(covH, covV, a, b, +1);\n                add_arc_cov(covH, covV, b, c2, +1);\n\n                if (ok && delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n\n            if (bestPos == -1) break;\n\n            int a = cyc[(bestPos - 1 + (int)cyc.size()) % (int)cyc.size()];\n            int b = cyc[bestPos];\n            int c2 = cyc[(bestPos + 1) % (int)cyc.size()];\n\n            add_arc_cov(covH, covV, a, b, -1);\n            add_arc_cov(covH, covV, b, c2, -1);\n            add_arc_cov(covH, covV, a, c2, +1);\n\n            cyc.erase(cyc.begin() + bestPos);\n        }\n    };\n\n    auto post_local_search_safe = [&](vector<int>& cyc) {\n        if ((int)cyc.size() <= 2) return;\n        int maxIter = ((int)cyc.size() <= 50 ? 8 : 4);\n        for (int iter = 0; iter < maxIter; iter++) {\n            ll curCost = cycleCost(cyc);\n            ll bestDelta = 0;\n            vector<int> bestCycle;\n            int sz = (int)cyc.size();\n\n            // relocate one\n            for (int i = 1; i < sz; i++) {\n                for (int after = 0; after < sz; after++) {\n                    if (after == i || after == i - 1) continue;\n                    vector<int> nc = cyc;\n                    int x = nc[i];\n                    nc.erase(nc.begin() + i);\n                    int pos = after;\n                    if (after > i) pos--;\n                    nc.insert(nc.begin() + pos + 1, x);\n\n                    ll delta = cycleCost(nc) - curCost;\n                    if (delta >= bestDelta) continue;\n                    if (!cycle_is_covered(nc)) continue;\n                    bestDelta = delta;\n                    bestCycle.swap(nc);\n                }\n            }\n\n            // swap\n            for (int i = 1; i < sz; i++) {\n                for (int j = i + 1; j < sz; j++) {\n                    vector<int> nc = cyc;\n                    swap(nc[i], nc[j]);\n                    ll delta = cycleCost(nc) - curCost;\n                    if (delta >= bestDelta) continue;\n                    if (!cycle_is_covered(nc)) continue;\n                    bestDelta = delta;\n                    bestCycle.swap(nc);\n                }\n            }\n\n            if (bestDelta < 0) cyc.swap(bestCycle);\n            else break;\n        }\n    };\n\n    auto build_full_path = [&](const vector<int>& cyc) {\n        vector<int> path;\n        path.push_back(startCell);\n        for (int idx = 0; idx < (int)cyc.size(); idx++) {\n            int s = cyc[idx];\n            int t = cyc[(idx + 1) % cyc.size()];\n            int sCell = relCells[s];\n            int tCell = relCells[t];\n            if (sCell == tCell) continue;\n\n            vector<int> rev;\n            int cur = tCell;\n            while (cur != sCell) {\n                int p = prevs[s][cur];\n                if (p == -1) break;\n                rev.push_back(cur);\n                cur = p;\n            }\n            reverse(rev.begin(), rev.end());\n            for (int x : rev) path.push_back(x);\n        }\n        return path;\n    };\n\n    auto shorten_full_path = [&](vector<int>& path) {\n        auto path_full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2,\n                                     const vector<int>& touchedCells) -> bool {\n            for (int cell : touchedCells) {\n                if (cntH2[cellH[cell]] == 0 && cntV2[cellV[cell]] == 0) return false;\n            }\n            return true;\n        };\n\n        vector<int> cntPathH(Hcnt, 0), cntPathV(Vcnt, 0);\n        for (int cell : path) {\n            cntPathH[cellH[cell]]++;\n            cntPathV[cellV[cell]]++;\n        }\n\n        vector<int> markH(Hcnt, -1), markV(Vcnt, -1), markCell(M, -1);\n        vector<int> decH(Hcnt, 0), decV(Vcnt, 0);\n        int stamp2 = 0;\n\n        while (true) {\n            int L = (int)path.size();\n            if (L <= 1) break;\n\n            vector<ll> pref(L, 0);\n            for (int i = 1; i < L; i++) pref[i] = pref[i - 1] + enterCost[path[i]];\n\n            vector<vector<int>> occ(M);\n            ll bestSave = 0;\n            int bestL = -1, bestR = -1;\n\n            for (int p = 0; p < L; p++) {\n                int cell = path[p];\n                auto &vec = occ[cell];\n\n                int checks = 0;\n                for (int z = (int)vec.size() - 1; z >= 0 && checks < 8; z--, checks++) {\n                    int l = vec[z];\n                    if (p <= l) continue;\n                    ll save = pref[p] - pref[l];\n                    if (save <= bestSave) continue;\n\n                    stamp2++;\n                    vector<int> touchedHs, touchedVs, touchedCells;\n\n                    for (int q = l + 1; q <= p; q++) {\n                        int x = path[q];\n                        int h = cellH[x], v = cellV[x];\n\n                        if (markH[h] != stamp2) {\n                            markH[h] = stamp2;\n                            decH[h] = 0;\n                            touchedHs.push_back(h);\n                        }\n                        if (markV[v] != stamp2) {\n                            markV[v] = stamp2;\n                            decV[v] = 0;\n                            touchedVs.push_back(v);\n                        }\n                        decH[h]++;\n                        decV[v]++;\n\n                        if (markCell[x] != stamp2) {\n                            markCell[x] = stamp2;\n                            touchedCells.push_back(x);\n                        }\n                    }\n\n                    for (int h : touchedHs) cntPathH[h] -= decH[h];\n                    for (int v : touchedVs) cntPathV[v] -= decV[v];\n\n                    for (int h : touchedHs) {\n                        for (int cell2 : cellsOfH[h]) {\n                            if (markCell[cell2] != stamp2) {\n                                markCell[cell2] = stamp2;\n                                touchedCells.push_back(cell2);\n                            }\n                        }\n                    }\n                    for (int v : touchedVs) {\n                        for (int cell2 : cellsOfV[v]) {\n                            if (markCell[cell2] != stamp2) {\n                                markCell[cell2] = stamp2;\n                                touchedCells.push_back(cell2);\n                            }\n                        }\n                    }\n\n                    bool ok = path_full_covered(cntPathH, cntPathV, touchedCells);\n\n                    for (int h : touchedHs) cntPathH[h] += decH[h];\n                    for (int v : touchedVs) cntPathV[v] += decV[v];\n\n                    if (ok) {\n                        bestSave = save;\n                        bestL = l;\n                        bestR = p;\n                    }\n                }\n\n                vec.push_back(p);\n            }\n\n            if (bestSave <= 0) break;\n\n            for (int q = bestL + 1; q <= bestR; q++) {\n                int x = path[q];\n                cntPathH[cellH[x]]--;\n                cntPathV[cellV[x]]--;\n            }\n            path.erase(path.begin() + bestL + 1, path.begin() + bestR + 1);\n        }\n    };\n\n    auto pathCost = [&](const vector<int>& path) -> ll {\n        ll ret = 0;\n        for (int i = 1; i < (int)path.size(); i++) ret += enterCost[path[i]];\n        return ret;\n    };\n\n    auto process_cycle = [&](vector<int> cyc) {\n        pre_local_search(cyc);\n        for (int rep = 0; rep < 2; rep++) {\n            delete_waypoints(cyc);\n            post_local_search_safe(cyc);\n        }\n        delete_waypoints(cyc);\n        vector<int> path = build_full_path(cyc);\n        shorten_full_path(path);\n        return path;\n    };\n\n    vector<vector<int>> initCycles;\n    initCycles.push_back(build_initial_cheapest_insertion());\n    if (R >= 2) {\n        initCycles.push_back(build_initial_nearest_neighbor());\n        initCycles.push_back(build_initial_farthest_insertion());\n        initCycles.push_back(build_initial_angle(false));\n        initCycles.push_back(build_initial_angle(true));\n    }\n\n    vector<vector<int>> uniqueCycles;\n    for (auto &cyc : initCycles) {\n        bool dup = false;\n        for (auto &u : uniqueCycles) {\n            if (u == cyc) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniqueCycles.push_back(cyc);\n    }\n\n    vector<vector<int>> candidatePaths;\n    for (auto cyc : uniqueCycles) {\n        candidatePaths.push_back(process_cycle(cyc));\n    }\n\n    int bestIdx = 0;\n    ll bestCost = pathCost(candidatePaths[0]);\n    for (int i = 1; i < (int)candidatePaths.size(); i++) {\n        ll cur = pathCost(candidatePaths[i]);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestIdx = i;\n        }\n    }\n    vector<int> bestPath = candidatePaths[bestIdx];\n\n    auto dirChar = [&](int a, int b) -> char {\n        int ra = rr[a], ca = cc[a];\n        int rb = rr[b], cb = cc[b];\n        if (rb == ra - 1 && cb == ca) return 'U';\n        if (rb == ra + 1 && cb == ca) return 'D';\n        if (rb == ra && cb == ca - 1) return 'L';\n        return 'R';\n    };\n\n    string ans;\n    for (int i = 1; i < (int)bestPath.size(); i++) {\n        ans.push_back(dirChar(bestPath[i - 1], bestPath[i]));\n    }\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 1000;\n\nstruct Observation {\n    int task;\n    int t;\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>> children(N), parents(N);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        children[u].push_back(v);\n        parents[v].push_back(u);\n    }\n\n    // ----------------------------\n    // Precompute task statistics\n    // ----------------------------\n    vector<int> indeg(N), rem_pre(N), outdeg(N, 0), sumd(N, 0);\n    vector<int> maxd(K, 0);\n    vector<double> avgd(K, 0.0);\n\n    for (int i = 0; i < N; ++i) {\n        indeg[i] = (int)parents[i].size();\n        rem_pre[i] = indeg[i];\n        outdeg[i] = (int)children[i].size();\n        for (int k = 0; k < K; ++k) {\n            sumd[i] += d[i][k];\n            maxd[k] = max(maxd[k], d[i][k]);\n            avgd[k] += d[i][k];\n        }\n    }\n    for (int k = 0; k < K; ++k) avgd[k] /= N;\n\n    // Initial skill guess\n    vector<int> init_skill(K);\n    for (int k = 0; k < K; ++k) {\n        int v = (int)llround(avgd[k] * 1.6);\n        v = max(0, min(v, maxd[k]));\n        init_skill[k] = v;\n    }\n\n    // Descendant count by bitset DP\n    vector<bitset<MAXN>> reach(N);\n    vector<int> desc_cnt(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        for (int ch : children[i]) {\n            reach[i] |= reach[ch];\n            reach[i].set(ch);\n        }\n        desc_cnt[i] = (int)reach[i].count();\n    }\n\n    // Weighted bottom level\n    vector<long long> bottom(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        long long best_child = 0;\n        for (int ch : children[i]) best_child = max(best_child, bottom[ch]);\n        long long node_w = sumd[i] + 5;\n        bottom[i] = node_w + best_child;\n    }\n\n    vector<long long> base_priority(N, 0);\n    for (int i = 0; i < N; ++i) {\n        base_priority[i] =\n            bottom[i] * 30LL +\n            desc_cnt[i] * 5LL +\n            outdeg[i] * 20LL +\n            sumd[i];\n    }\n\n    auto calc_w_with_skill = [&](int task, const vector<int>& skill) -> int {\n        int w = 0;\n        for (int k = 0; k < K; ++k) {\n            if (d[task][k] > skill[k]) w += d[task][k] - skill[k];\n        }\n        return w;\n    };\n\n    vector<int> default_w(N), default_t(N);\n    for (int i = 0; i < N; ++i) {\n        default_w[i] = calc_w_with_skill(i, init_skill);\n        default_t[i] = max(1, default_w[i]);\n    }\n\n    // ----------------------------\n    // Online state\n    // ----------------------------\n    // -1: not started, 0: in progress, 1: completed\n    vector<int> task_status(N, -1);\n\n    vector<int> current_task(M, -1);\n    vector<int> start_day(M, -1);\n\n    vector<vector<int>> skill_hat(M, init_skill);\n    vector<vector<Observation>> obs(M);\n\n    auto loss_interval = [&](int w, int t) -> double {\n        int L, U;\n        if (t <= 1) {\n            // t=1 can happen for w up to 4\n            L = 0;\n            U = 4;\n        } else {\n            L = max(0, t - 3);\n            U = t + 3;\n        }\n\n        double dist = 0.0;\n        if (w < L) dist = (double)(L - w);\n        else if (w > U) dist = (double)(w - U);\n        else dist = 0.0;\n\n        double weight = (t <= 1 ? 1.0 : 1.0 + 0.05 * min(t, 20));\n        return dist * dist * weight;\n    };\n\n    auto optimize_member = [&](int j) {\n        int T = (int)obs[j].size();\n        if (T == 0) return;\n\n        vector<int>& s = skill_hat[j];\n        vector<int> curW(T);\n        for (int idx = 0; idx < T; ++idx) {\n            curW[idx] = calc_w_with_skill(obs[j][idx].task, s);\n        }\n\n        const int max_iter = 3;\n        for (int it = 0; it < max_iter; ++it) {\n            bool changed = false;\n\n            for (int k = 0; k < K; ++k) {\n                int prev = s[k];\n\n                vector<int> base(T);\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    base[idx] = curW[idx] - max(0, d[task][k] - prev);\n                }\n\n                double best_obj = 1e100;\n                int best_x = prev;\n                int best_tie1 = 0;\n                int best_tie2 = abs(prev - init_skill[k]);\n\n                for (int x = 0; x <= maxd[k]; ++x) {\n                    double obj = 0.0;\n                    for (int idx = 0; idx < T; ++idx) {\n                        int task = obs[j][idx].task;\n                        int w = base[idx] + max(0, d[task][k] - x);\n                        obj += loss_interval(w, obs[j][idx].t);\n                    }\n\n                    obj += 0.02 * (x - init_skill[k]) * (x - init_skill[k]);\n\n                    int tie1 = abs(x - prev);\n                    int tie2 = abs(x - init_skill[k]);\n                    if (obj + 1e-9 < best_obj ||\n                        (abs(obj - best_obj) <= 1e-9 &&\n                         (tie1 < best_tie1 || (tie1 == best_tie1 && tie2 < best_tie2)))) {\n                        best_obj = obj;\n                        best_x = x;\n                        best_tie1 = tie1;\n                        best_tie2 = tie2;\n                    }\n                }\n\n                if (best_x != prev) changed = true;\n                s[k] = best_x;\n\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    curW[idx] = base[idx] + max(0, d[task][k] - best_x);\n                }\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto estimate_time = [&](int member, int task) -> double {\n        double trust = (double)obs[member].size() / ((double)obs[member].size() + 5.0);\n        int learned_w = calc_w_with_skill(task, skill_hat[member]);\n        double p = (1.0 - trust) * default_w[task] + trust * learned_w;\n        p += (1.0 - trust) * 0.10 * default_w[task];\n        return max(1.0, p);\n    };\n\n    auto get_ready_tasks = [&]() -> vector<int> {\n        vector<int> ready;\n        ready.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (task_status[i] == -1 && rem_pre[i] == 0) ready.push_back(i);\n        }\n        return ready;\n    };\n\n    auto calc_unlock_bonus = [&](int task) -> pair<int, long long> {\n        int cnt = 0;\n        long long child_bottom_sum = 0;\n        for (int ch : children[task]) {\n            if (task_status[ch] == -1 && rem_pre[ch] == 1) {\n                ++cnt;\n                child_bottom_sum += bottom[ch];\n            }\n        }\n        return {cnt, child_bottom_sum};\n    };\n\n    auto dynamic_priority = [&](int task) -> long long {\n        auto [cnt, child_sum] = calc_unlock_bonus(task);\n        return base_priority[task] + 400LL * cnt + child_sum * 8LL;\n    };\n\n    auto select_candidates = [&](const vector<int>& ready, int free_cnt) -> vector<int> {\n        int limit = max(60, free_cnt * 5);\n        if ((int)ready.size() <= limit) return ready;\n\n        vector<pair<long long,int>> by_pri;\n        vector<pair<int,int>> by_easy;\n        vector<pair<long long,int>> by_unlock;\n\n        by_pri.reserve(ready.size());\n        by_easy.reserve(ready.size());\n        by_unlock.reserve(ready.size());\n\n        for (int t : ready) {\n            auto [cnt, child_sum] = calc_unlock_bonus(t);\n            by_pri.push_back({dynamic_priority(t), t});\n            by_easy.push_back({default_t[t], t});\n            by_unlock.push_back({(long long)cnt * 1000000LL + child_sum, t});\n        }\n\n        sort(by_pri.begin(), by_pri.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n        sort(by_easy.begin(), by_easy.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first < b.first;\n            return a.second < b.second;\n        });\n        sort(by_unlock.begin(), by_unlock.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int take_pri = max(25, free_cnt * 3);\n        int take_easy = max(15, free_cnt * 2);\n        int take_unlock = max(15, free_cnt * 2);\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(limit + 10);\n\n        for (int i = 0; i < (int)by_pri.size() && (int)cand.size() < take_pri; ++i) {\n            int t = by_pri[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_easy.size() && i < take_easy; ++i) {\n            int t = by_easy[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_unlock.size() && i < take_unlock; ++i) {\n            int t = by_unlock[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (auto &p : by_pri) {\n            if ((int)cand.size() >= limit) break;\n            int t = p.second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        return cand;\n    };\n\n    auto decide_assignments = [&]() -> vector<pair<int,int>> {\n        vector<int> free_members;\n        for (int j = 0; j < M; ++j) {\n            if (current_task[j] == -1) free_members.push_back(j);\n        }\n\n        vector<int> ready = get_ready_tasks();\n        if (free_members.empty() || ready.empty()) return {};\n\n        vector<int> cand = select_candidates(ready, (int)free_members.size());\n\n        int F = (int)free_members.size();\n        int C = (int)cand.size();\n\n        vector<long long> pri(C);\n        vector<int> unlock_cnt(C);\n        for (int ci = 0; ci < C; ++ci) {\n            auto [cnt, _] = calc_unlock_bonus(cand[ci]);\n            pri[ci] = dynamic_priority(cand[ci]);\n            unlock_cnt[ci] = cnt;\n        }\n\n        vector<vector<double>> pred(F, vector<double>(C));\n        vector<double> best_t(C, 1e100);\n\n        for (int fi = 0; fi < F; ++fi) {\n            int mem = free_members[fi];\n            for (int ci = 0; ci < C; ++ci) {\n                pred[fi][ci] = estimate_time(mem, cand[ci]);\n                best_t[ci] = min(best_t[ci], pred[fi][ci]);\n            }\n        }\n\n        // Greedy matching\n        const long long TIME_PENALTY = 850;\n        const long long GAP_PENALTY = 250;\n        const long long UNKNOWN_LONG_PENALTY = 35;\n        const long long UNKNOWN_UNLOCK_PENALTY = 120;\n\n        vector<char> used_f(F, 0), used_c(C, 0);\n        vector<pair<int,int>> ret;\n        ret.reserve(min(F, C));\n\n        for (int step = 0; step < min(F, C); ++step) {\n            long long best_score = LLONG_MIN;\n            int best_f = -1, best_c = -1;\n\n            for (int fi = 0; fi < F; ++fi) if (!used_f[fi]) {\n                int mem = free_members[fi];\n                int seen = (int)obs[mem].size();\n\n                for (int ci = 0; ci < C; ++ci) if (!used_c[ci]) {\n                    double et = pred[fi][ci];\n                    double gap = et - best_t[ci];\n\n                    long long score = pri[ci]\n                        - (long long)llround(et * TIME_PENALTY)\n                        - (long long)llround(gap * GAP_PENALTY);\n\n                    // Be cautious with untrained members on long tasks\n                    if (seen < 4) {\n                        double extra = max(0.0, et - 8.0) * (4 - seen);\n                        score -= (long long)llround(extra * UNKNOWN_LONG_PENALTY);\n                    }\n\n                    // Additional mild caution:\n                    // tasks that immediately unlock many children should preferably\n                    // be assigned to better-understood members.\n                    if (seen < 3 && unlock_cnt[ci] > 0) {\n                        score -= 1LL * (3 - seen) * unlock_cnt[ci] * UNKNOWN_UNLOCK_PENALTY;\n                    }\n\n                    if (score > best_score) {\n                        best_score = score;\n                        best_f = fi;\n                        best_c = ci;\n                    }\n                }\n            }\n\n            if (best_f == -1) break;\n            used_f[best_f] = 1;\n            used_c[best_c] = 1;\n            ret.emplace_back(free_members[best_f], cand[best_c]);\n        }\n\n        return ret;\n    };\n\n    // ----------------------------\n    // Interactive loop\n    // ----------------------------\n    int day = 0;\n    while (true) {\n        ++day;\n\n        vector<pair<int,int>> assigns = decide_assignments();\n\n        for (auto [mem, task] : assigns) {\n            task_status[task] = 0;\n            current_task[mem] = task;\n            start_day[mem] = day;\n        }\n\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) {\n            cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        }\n        cout << '\\n' << flush;\n\n        int nfin;\n        cin >> nfin;\n        if (!cin) return 0;\n        if (nfin == -1) return 0;\n\n        vector<int> finished(nfin);\n        for (int i = 0; i < nfin; ++i) {\n            cin >> finished[i];\n            --finished[i];\n        }\n\n        for (int mem : finished) {\n            int task = current_task[mem];\n            if (task == -1) continue;\n\n            int duration = day - start_day[mem] + 1;\n            obs[mem].push_back({task, duration});\n\n            task_status[task] = 1;\n            current_task[mem] = -1;\n            start_day[mem] = -1;\n\n            for (int ch : children[task]) {\n                --rem_pre[ch];\n            }\n\n            optimize_member(mem);\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 1000;\nstatic constexpr int TOT = 2001; // 0: office, 1..1000 pickup, 1001..2000 delivery\nstatic constexpr double TL = 1.90;\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 XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Insertion {\n    int delta;\n    int g1, g2;\n};\n\nstruct SingleInsertion {\n    int delta;\n    int g;\n};\n\nstruct State {\n    vector<int> seq;\n    vector<char> selected;\n    int cost = 0;\n};\n\nint X[TOT], Y[TOT];\nvector<int> DM;\nint baseScore[N + 1];\nvector<int> sorted_ids;\n\ninline int dist_node(int a, int b) {\n    return DM[a * TOT + b];\n}\ninline int pickup_node(int id) { return id; }\ninline int delivery_node(int id) { return N + id; }\n\nint route_cost(const vector<int>& seq) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)seq.size(); i++) s += dist_node(seq[i], seq[i + 1]);\n    return s;\n}\n\nvector<int> get_selected_ids(const vector<char>& selected) {\n    vector<int> ids;\n    ids.reserve(50);\n    for (int id = 1; id <= N; id++) if (selected[id]) ids.push_back(id);\n    return ids;\n}\n\nInsertion find_best_insertion(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    const int m = (int)seq.size();\n\n    Insertion best{INT_MAX, -1, -1};\n\n    for (int g1 = 0; g1 < m - 1; g1++) {\n        int a = seq[g1], b = seq[g1 + 1];\n        int dab = dist_node(a, b);\n\n        int delta_same = dist_node(a, u) + dist_node(u, v) + dist_node(v, b) - dab;\n        if (delta_same < best.delta) best = {delta_same, g1, g1};\n\n        int delta_pick = dist_node(a, u) + dist_node(u, b) - dab;\n        for (int g2 = g1 + 1; g2 < m - 1; g2++) {\n            int c = seq[g2], d = seq[g2 + 1];\n            int delta = delta_pick + dist_node(c, v) + dist_node(v, d) - dist_node(c, d);\n            if (delta < best.delta) best = {delta, g1, g2};\n        }\n    }\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& seq, int id, const Insertion& ins) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() + 2);\n\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == ins.g1) {\n            res.push_back(u);\n            if (ins.g2 == ins.g1) res.push_back(v);\n        }\n        if (i == ins.g2 && ins.g2 > ins.g1) {\n            res.push_back(v);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() - 2);\n    for (int x : seq) {\n        if (x != u && x != v) res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> remove_orders(const vector<int>& seq, const vector<int>& rem_ids) {\n    vector<char> bad(N + 1, 0);\n    for (int id : rem_ids) bad[id] = 1;\n    vector<int> res;\n    res.reserve(seq.size() - 2 * (int)rem_ids.size());\n    for (int x : seq) {\n        if (x == 0) {\n            res.push_back(x);\n        } else {\n            int id = (x <= N ? x : x - N);\n            if (!bad[id]) res.push_back(x);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_node_once(const vector<int>& seq, int node) {\n    vector<int> res;\n    res.reserve(seq.size() - 1);\n    bool skipped = false;\n    for (int x : seq) {\n        if (!skipped && x == node) {\n            skipped = true;\n            continue;\n        }\n        res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> insert_single_node(const vector<int>& seq, int node, int g) {\n    vector<int> res;\n    res.reserve(seq.size() + 1);\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == g) res.push_back(node);\n    }\n    return res;\n}\n\nSingleInsertion find_best_single_insertion(const vector<int>& seq, int node, int gl, int gr) {\n    int m = (int)seq.size();\n    gl = max(gl, 0);\n    gr = min(gr, m - 2);\n\n    SingleInsertion best{INT_MAX, -1};\n    for (int g = gl; g <= gr; g++) {\n        int a = seq[g], b = seq[g + 1];\n        int delta = dist_node(a, node) + dist_node(node, b) - dist_node(a, b);\n        if (delta < best.delta) best = {delta, g};\n    }\n    return best;\n}\n\nint pick_rcl_index(int sz, XorShift64& rng) {\n    if (sz <= 1) return 0;\n    int r = rng.next_int(0, 99);\n    if (sz == 2) return (r < 72 ? 0 : 1);\n    if (sz == 3) return (r < 55 ? 0 : (r < 85 ? 1 : 2));\n    if (sz == 4) return (r < 45 ? 0 : (r < 73 ? 1 : (r < 90 ? 2 : 3)));\n    if (sz == 5) return (r < 42 ? 0 : (r < 68 ? 1 : (r < 84 ? 2 : (r < 94 ? 3 : 4))));\n    return (r < 40 ? 0 : (r < 64 ? 1 : (r < 79 ? 2 : (r < 89 ? 3 : (r < 96 ? 4 : 5)))));\n}\n\nstruct Cand {\n    int delta;\n    int id;\n    Insertion ins;\n};\n\nvoid push_top_k(vector<Cand>& top, const Cand& c, int topK) {\n    if ((int)top.size() < topK) {\n        top.push_back(c);\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            return baseScore[a.id] < baseScore[b.id];\n        });\n    } else {\n        const auto& w = top.back();\n        if (c.delta < w.delta || (c.delta == w.delta && baseScore[c.id] < baseScore[w.id])) {\n            top.back() = c;\n            sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                if (a.delta != b.delta) return a.delta < b.delta;\n                return baseScore[a.id] < baseScore[b.id];\n            });\n        }\n    }\n}\n\nvector<Cand> collect_top_insertions(\n    const vector<int>& seq,\n    const vector<char>& selected,\n    int limit_ids,\n    int topK,\n    const Timer* timer = nullptr,\n    double end_time = 1e100\n) {\n    vector<Cand> top;\n    top.reserve(topK);\n\n    int lim = min(limit_ids, (int)sorted_ids.size());\n    for (int i = 0; i < lim; i++) {\n        if (timer && timer->elapsed() >= end_time) break;\n        int id = sorted_ids[i];\n        if (selected[id]) continue;\n        Insertion ins = find_best_insertion(seq, id);\n        push_top_k(top, Cand{ins.delta, id, ins}, topK);\n    }\n\n    if (top.empty()) {\n        for (int id = 1; id <= N; id++) {\n            if (selected[id]) continue;\n            Insertion ins = find_best_insertion(seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n    }\n\n    return top;\n}\n\nState construct_solution(int pool_limit, bool randomized, XorShift64& rng, const Timer& timer, double end_time) {\n    State st;\n    st.seq = {0, 0};\n    st.selected.assign(N + 1, 0);\n    st.cost = 0;\n\n    int cnt = 0;\n    int topK = randomized ? 6 : 1;\n\n    while (cnt < 50) {\n        if (timer.elapsed() >= end_time) break;\n        auto top = collect_top_insertions(st.seq, st.selected, pool_limit, topK, &timer, end_time);\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    while (cnt < 50) {\n        auto top = collect_top_insertions(st.seq, st.selected, N, 1);\n        auto chosen = top[0];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    return st;\n}\n\nState rebuild_route_for_selected(const vector<char>& selected, bool randomized, XorShift64& rng) {\n    vector<int> ids = get_selected_ids(selected);\n\n    State st;\n    st.seq = {0, 0};\n    st.selected = selected;\n    st.cost = 0;\n\n    vector<char> used(N + 1, 0);\n    int topK = randomized ? 5 : 1;\n\n    for (int step = 0; step < 50; step++) {\n        vector<Cand> top;\n        top.reserve(topK);\n        for (int id : ids) {\n            if (used[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.cost += chosen.delta;\n        used[chosen.id] = 1;\n    }\n    return st;\n}\n\nbool improve_adjacent_swap(State& st, const Timer& timer, double end_time, int max_passes = 20) {\n    bool any = false;\n    int m = (int)st.seq.size();\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_delta = 0;\n        int best_i = -1;\n\n        for (int i = 1; i + 2 < m; i++) {\n            if (timer.elapsed() >= end_time) break;\n            int a = st.seq[i];\n            int b = st.seq[i + 1];\n            if (a == 0 || b == 0) continue;\n\n            // invalid only when swapping pickup(id), delivery(id)\n            if (a <= N && b == N + a) continue;\n\n            int prev = st.seq[i - 1];\n            int next = st.seq[i + 2];\n\n            int delta = dist_node(prev, b) + dist_node(b, a) + dist_node(a, next)\n                      - dist_node(prev, a) - dist_node(a, b) - dist_node(b, next);\n\n            if (delta < best_delta) {\n                best_delta = delta;\n                best_i = i;\n            }\n        }\n\n        if (best_i == -1) break;\n        swap(st.seq[best_i], st.seq[best_i + 1]);\n        st.cost += best_delta;\n        any = true;\n    }\n\n    return any;\n}\n\nbool improve_event_relocate(State& st, const Timer& timer, double end_time, int max_passes = 50) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        vector<int> pos(TOT, -1);\n        for (int i = 0; i < (int)st.seq.size(); i++) pos[st.seq[i]] = i;\n\n        int best_new_cost = st.cost;\n        int best_node = -1;\n        int best_gap = -1;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            int u = pickup_node(id);\n            int v = delivery_node(id);\n            int pu = pos[u];\n            int pv = pos[v];\n\n            // move pickup only\n            {\n                int prev = st.seq[pu - 1];\n                int next = st.seq[pu + 1];\n                int cost_removed = st.cost - (dist_node(prev, u) + dist_node(u, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, u);\n\n                int pdr = pv - 1;\n                auto ins = find_best_single_insertion(seq_removed, u, 0, pdr - 1);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = u;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n\n            // move delivery only\n            {\n                int prev = st.seq[pv - 1];\n                int next = st.seq[pv + 1];\n                int cost_removed = st.cost - (dist_node(prev, v) + dist_node(v, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, v);\n\n                int ppr = pu;\n                auto ins = find_best_single_insertion(seq_removed, v, ppr, (int)seq_removed.size() - 2);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = v;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n        }\n\n        if (best_node == -1) break;\n        vector<int> seq_removed = remove_node_once(st.seq, best_node);\n        st.seq = insert_single_node(seq_removed, best_node, best_gap);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\nbool improve_pair_relocate(State& st, const Timer& timer, double end_time, int max_passes = 100) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_new_cost = st.cost;\n        int best_id = -1;\n        Insertion best_ins;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int cost_removed = route_cost(seq_removed);\n            Insertion ins = find_best_insertion(seq_removed, id);\n            int new_cost = cost_removed + ins.delta;\n\n            if (new_cost < best_new_cost) {\n                best_new_cost = new_cost;\n                best_id = id;\n                best_ins = ins;\n            }\n        }\n\n        if (best_id == -1) break;\n        vector<int> seq_removed = remove_order(st.seq, best_id);\n        st.seq = apply_insertion(seq_removed, best_id, best_ins);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\n// reversing [l, r] is valid iff no order has both endpoints inside [l, r]\nbool improve_two_opt(State& st, const Timer& timer, double end_time, int max_passes = 20) {\n    bool any = false;\n    int m = (int)st.seq.size();\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_delta = 0;\n        int best_l = -1, best_r = -1;\n        vector<int> cnt(N + 1, 0);\n\n        for (int l = 1; l <= m - 3; l++) {\n            if (timer.elapsed() >= end_time) break;\n            fill(cnt.begin(), cnt.end(), 0);\n\n            for (int r = l; r <= m - 2; r++) {\n                int node = st.seq[r];\n                if (node == 0) break;\n                int id = (node <= N ? node : node - N);\n                cnt[id]++;\n                if (cnt[id] == 2) break;\n\n                int delta =\n                    dist_node(st.seq[l - 1], st.seq[r]) +\n                    dist_node(st.seq[l], st.seq[r + 1]) -\n                    dist_node(st.seq[l - 1], st.seq[l]) -\n                    dist_node(st.seq[r], st.seq[r + 1]);\n\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_l = l;\n                    best_r = r;\n                }\n            }\n        }\n\n        if (best_l == -1) break;\n        reverse(st.seq.begin() + best_l, st.seq.begin() + best_r + 1);\n        st.cost += best_delta;\n        any = true;\n    }\n\n    return any;\n}\n\nvoid optimize_route(State& st, const Timer& timer, double end_time) {\n    while (timer.elapsed() < end_time) {\n        int old_cost = st.cost;\n\n        double t0 = min(end_time, timer.elapsed() + 0.018);\n        improve_two_opt(st, timer, t0, 3);\n\n        double t1 = min(end_time, timer.elapsed() + 0.010);\n        improve_adjacent_swap(st, timer, t1, 4);\n\n        double t2 = min(end_time, timer.elapsed() + 0.018);\n        improve_event_relocate(st, timer, t2, 3);\n\n        double t3 = min(end_time, timer.elapsed() + 0.018);\n        improve_pair_relocate(st, timer, t3, 2);\n\n        if (st.cost >= old_cost) break;\n    }\n}\n\nvoid improve_swap(State& st, const Timer& timer, double end_time) {\n    const int TOP_REMOVE = 12;\n    const int TOP_ADD = 120;\n\n    while (timer.elapsed() < end_time) {\n        struct RemCand {\n            int gain;\n            int id;\n        };\n        vector<RemCand> rems;\n        rems.reserve(50);\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int removed_cost = route_cost(seq_removed);\n            int gain = st.cost - removed_cost;\n            rems.push_back({gain, id});\n        }\n\n        sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.id < b.id;\n        });\n        if ((int)rems.size() > TOP_REMOVE) rems.resize(TOP_REMOVE);\n\n        vector<Cand> adds;\n        adds.reserve(TOP_ADD);\n        for (int id = 1; id <= N; id++) {\n            if (timer.elapsed() >= end_time) break;\n            if (st.selected[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(adds, Cand{ins.delta, id, ins}, TOP_ADD);\n        }\n\n        int best_new_cost = st.cost;\n        int best_remove = -1, best_add = -1;\n        Insertion best_ins;\n\n        for (const auto& rc : rems) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> seq_removed = remove_order(st.seq, rc.id);\n            int cost_removed = route_cost(seq_removed);\n\n            for (const auto& ac : adds) {\n                Insertion ins = find_best_insertion(seq_removed, ac.id);\n                int new_cost = cost_removed + ins.delta;\n                if (new_cost < best_new_cost) {\n                    best_new_cost = new_cost;\n                    best_remove = rc.id;\n                    best_add = ac.id;\n                    best_ins = ins;\n                }\n            }\n        }\n\n        if (best_remove == -1) break;\n\n        st.selected[best_remove] = 0;\n        st.selected[best_add] = 1;\n        vector<int> seq_removed = remove_order(st.seq, best_remove);\n        st.seq = apply_insertion(seq_removed, best_add, best_ins);\n        st.cost = best_new_cost;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(st, timer, sub_end);\n    }\n}\n\nbool destroy_and_repair_once(State& st, const Timer& timer, double end_time, XorShift64& rng) {\n    if (timer.elapsed() >= end_time) return false;\n\n    auto selected_ids = get_selected_ids(st.selected);\n\n    struct RemCand {\n        int gain;\n        int id;\n    };\n    vector<RemCand> rems;\n    rems.reserve(50);\n    for (int id : selected_ids) {\n        vector<int> seq_removed = remove_order(st.seq, id);\n        int removed_cost = route_cost(seq_removed);\n        int gain = st.cost - removed_cost;\n        rems.push_back({gain, id});\n    }\n    sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        return a.id < b.id;\n    });\n\n    int elite_rem = min(12, (int)rems.size());\n\n    for (int trial = 0; trial < 12 && timer.elapsed() < end_time; trial++) {\n        int k = (rng.next_int(0, 99) < 70 ? 2 : 3);\n\n        vector<int> remset;\n        remset.reserve(k);\n        while ((int)remset.size() < k) {\n            int id;\n            if (rng.next_int(0, 99) < 80) {\n                id = rems[rng.next_int(0, elite_rem - 1)].id;\n            } else {\n                id = selected_ids[rng.next_int(0, (int)selected_ids.size() - 1)];\n            }\n            bool dup = false;\n            for (int x : remset) if (x == id) dup = true;\n            if (!dup) remset.push_back(id);\n        }\n\n        State tmp;\n        tmp.selected = st.selected;\n        for (int id : remset) tmp.selected[id] = 0;\n        tmp.seq = remove_orders(st.seq, remset);\n        tmp.cost = route_cost(tmp.seq);\n\n        for (int rep = 0; rep < k; rep++) {\n            if (timer.elapsed() >= end_time) break;\n            auto top = collect_top_insertions(tmp.seq, tmp.selected, 800, 6, &timer, end_time);\n            int idx = pick_rcl_index((int)top.size(), rng);\n            auto chosen = top[idx];\n            tmp.seq = apply_insertion(tmp.seq, chosen.id, chosen.ins);\n            tmp.selected[chosen.id] = 1;\n            tmp.cost += chosen.delta;\n        }\n\n        if ((int)get_selected_ids(tmp.selected).size() != 50) continue;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(tmp, timer, sub_end);\n\n        if (tmp.cost < st.cost) {\n            st = move(tmp);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    X[0] = 400;\n    Y[0] = 400;\n\n    long long seed = 123456789;\n\n    for (int i = 1; i <= N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        X[i] = a;\n        Y[i] = b;\n        X[N + i] = c;\n        Y[N + i] = d;\n\n        int d0p = abs(400 - a) + abs(400 - b);\n        int dpd = abs(a - c) + abs(b - d);\n        int dd0 = abs(c - 400) + abs(d - 400);\n        int center_sum = d0p + dd0;\n        baseScore[i] = 3 * (d0p + dpd + dd0) + center_sum;\n\n        seed = seed * 1000003 + a * 911 + b * 3571 + c * 1021 + d;\n    }\n\n    DM.assign(TOT * TOT, 0);\n    for (int i = 0; i < TOT; i++) {\n        for (int j = 0; j < TOT; j++) {\n            DM[i * TOT + j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n        }\n    }\n\n    sorted_ids.resize(N);\n    iota(sorted_ids.begin(), sorted_ids.end(), 1);\n    sort(sorted_ids.begin(), sorted_ids.end(), [](int i, int j) {\n        if (baseScore[i] != baseScore[j]) return baseScore[i] < baseScore[j];\n        return i < j;\n    });\n\n    Timer timer;\n    XorShift64 rng((uint64_t)seed);\n\n    State best;\n    bool has_best = false;\n\n    // Multi-start construction\n    vector<int> pool_limits = {140, 200, 280, 380, 520, 700, 1000};\n    int attempt = 0;\n    while (timer.elapsed() < 0.58) {\n        int pool = pool_limits[attempt % (int)pool_limits.size()];\n        bool randomized = (attempt > 0);\n        State st = construct_solution(pool, randomized, rng, timer, 0.62);\n\n        double sub_end = min(0.82, TL);\n        optimize_route(st, timer, sub_end);\n\n        if (!has_best || st.cost < best.cost) {\n            best = move(st);\n            has_best = true;\n        }\n        attempt++;\n    }\n\n    if (!has_best) {\n        best = construct_solution(1000, false, rng, timer, TL);\n    }\n\n    optimize_route(best, timer, 1.04);\n    improve_swap(best, timer, 1.30);\n    optimize_route(best, timer, 1.52);\n\n    int fail_dr = 0;\n    while (timer.elapsed() < 1.74 && fail_dr < 4) {\n        if (destroy_and_repair_once(best, timer, 1.78, rng)) {\n            fail_dr = 0;\n            double sub_end = min(1.80, TL);\n            optimize_route(best, timer, sub_end);\n        } else {\n            fail_dr++;\n        }\n    }\n\n    int rebuild_trials = 0;\n    while (timer.elapsed() < 1.84) {\n        bool randomized = (rebuild_trials % 3 != 0);\n        State cand = rebuild_route_for_selected(best.selected, randomized, rng);\n        double sub_end = min(1.87, TL);\n        optimize_route(cand, timer, sub_end);\n        if (cand.cost < best.cost) best = move(cand);\n        rebuild_trials++;\n    }\n\n    // Late short swap after DR/rebuild can still improve the selected set\n    improve_swap(best, timer, 1.885);\n    optimize_route(best, timer, TL - 0.01);\n\n    auto ids = get_selected_ids(best.selected);\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.seq.size();\n    for (int node : best.seq) {\n        cout << ' ' << X[node] << ' ' << Y[node];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int S = 64;   // even\nstatic constexpr int H = S / 2;\nstatic constexpr int INF = 1e9;\n\nstruct Edge {\n    int u, v, d;\n};\n\ntemplate <int MAXN>\nstruct UnionFind {\n    int p[MAXN], sz[MAXN];\n\n    inline void init(int n) {\n        for (int i = 0; i < n; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\n\n    inline int leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline int leader_const(int x) const {\n        while (p[x] != x) x = p[x];\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    inline bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 0x123456789abcdefULL) : 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(uint32_t mod) {\n        return (uint32_t)(next_u64() % mod);\n    }\n};\n\nstatic Edge edges[M];\nstatic int weights[S][M];\nstatic int orders[S][M];\nstatic int order_d[M];\n\n// Pure topological check on the remaining graph after contracting accepted components.\nstatic inline bool can_connect_future(\n    int next_idx,\n    int K,\n    const int cid[N]\n) {\n    if (K == 1) return true;\n\n    UnionFind<N> uf;\n    uf.init(K);\n    int need = K - 1;\n\n    for (int idx = next_idx; idx < M; ++idx) {\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n        if (uf.merge(a, b)) {\n            if (--need == 0) return true;\n        }\n    }\n    return false;\n}\n\n// Sampled world threshold: weight at which cu and cv first become connected in Kruskal.\nstatic inline int estimate_threshold_sample(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int cu,\n    int cv,\n    const int* order,\n    const int* weight\n) {\n    UnionFind<N> uf;\n    uf.init(K);\n\n    for (int t = 0; t < M; ++t) {\n        int idx = order[t];\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (uf.merge(a, b) && uf.same(cu, cv)) {\n            return weight[idx];\n        }\n    }\n    return INF;\n}\n\n// Deterministic baseline threshold using d-order.\n// Since mean edge length is 2*d, the baseline threshold is 2 * (threshold in d-order).\nstatic inline int estimate_threshold_d(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int cu,\n    int cv\n) {\n    UnionFind<N> uf;\n    uf.init(K);\n\n    for (int t = 0; t < M; ++t) {\n        int idx = order_d[t];\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (uf.merge(a, b) && uf.same(cu, cv)) {\n            return edges[idx].d;\n        }\n    }\n    return INF;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int xs[N], ys[N];\n    for (int i = 0; i < N; ++i) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = xs[u] - xs[v];\n        long long dy = ys[u] - ys[v];\n        int d = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Deterministic baseline order by d.\n    for (int i = 0; i < M; ++i) order_d[i] = i;\n    sort(order_d, order_d + M, [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    // Stratified antithetic sampling.\n    SplitMix64 rng(0x3141592653589793ULL);\n    vector<int> perm(H);\n\n    for (int i = 0; i < M; ++i) {\n        iota(perm.begin(), perm.end(), 0);\n        for (int j = H - 1; j >= 1; --j) {\n            int k = (int)rng.next_u32(j + 1);\n            swap(perm[j], perm[k]);\n        }\n\n        int d = edges[i].d;\n        int range = 2 * d + 1; // t in [0, 2d]\n\n        for (int k = 0; k < H; ++k) {\n            int q = perm[k];\n            int L = (long long)range * q / H;\n            int R = (long long)range * (q + 1) / H - 1;\n            if (R < L) R = L;\n            int t = (L + R) >> 1;\n\n            weights[2 * k][i] = d + t;\n            weights[2 * k + 1][i] = 3 * d - t;\n        }\n    }\n\n    for (int s = 0; s < S; ++s) {\n        for (int i = 0; i < M; ++i) orders[s][i] = i;\n        sort(orders[s], orders[s] + M, [&](int a, int b) {\n            if (weights[s][a] != weights[s][b]) return weights[s][a] < weights[s][b];\n            return a < b;\n        });\n    }\n\n    UnionFind<N> accepted;\n    accepted.init(N);\n\n    int cid[N];\n    int K = N;\n    bool comp_dirty = true;\n\n    auto rebuild_components = [&]() {\n        int mp[N];\n        for (int i = 0; i < N; ++i) mp[i] = -1;\n        K = 0;\n        for (int v = 0; v < N; ++v) {\n            int r = accepted.leader_const(v);\n            if (mp[r] == -1) mp[r] = K++;\n            cid[v] = mp[r];\n        }\n        comp_dirty = false;\n    };\n\n    for (int i = 0; i < M; ++i) {\n        int l;\n        cin >> l;\n\n        int u = edges[i].u;\n        int v = edges[i].v;\n        int ans = 0;\n\n        if (!accepted.same(u, v)) {\n            if (comp_dirty) rebuild_components();\n\n            int cu = cid[u];\n            int cv = cid[v];\n\n            if (!can_connect_future(i + 1, K, cid)) {\n                ans = 1;\n            } else {\n                long long sum_thr = 0;\n                for (int s = 0; s < S; ++s) {\n                    int thr = estimate_threshold_sample(i + 1, K, cid, cu, cv, orders[s], weights[s]);\n                    sum_thr += thr;\n                }\n                double sample_mean = (double)sum_thr / S;\n\n                int d_thr = estimate_threshold_d(i + 1, K, cid, cu, cv);\n                double baseline = 2.0 * d_thr;\n\n                // Mild shrinkage toward the deterministic baseline.\n                // More baseline weight when many components remain.\n                double rem_comp = (double)(K - 1) / (N - 1); // 1 early, 0 late\n                double alpha = 0.90 - 0.08 * rem_comp;       // ~0.82 early, ~0.90 late\n\n                double blended = alpha * sample_mean + (1.0 - alpha) * baseline;\n\n                if ((double)l <= blended) ans = 1;\n            }\n        }\n\n        if (ans) {\n            accepted.merge(u, v);\n            comp_dirty = true;\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n    bool operator==(const Pos& o) const { return x == o.x && y == o.y; }\n    bool operator!=(const Pos& o) const { return !(*this == o); }\n};\n\nstatic constexpr int B = 30;\nstatic constexpr int T = 300;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nvector<Pos> pets, humans;\nvector<int> petType;\nbool wallg[31][31];\n\n// outer room parameters in normalized (top-left) coordinates\nint chosenCorner = 0;\nint outerH = 8, outerW = 8;\n// keepDoorOuter = 0 : keep bottom door (outerH+1, outerW)\n// keepDoorOuter = 1 : keep right  door (outerH, outerW+1)\nint keepDoorOuter = 0;\n\n// current final human room after optional inner split\nint curH = 8, curW = 8;\n\n// parking targets for current human objective region\nvector<Pos> parkTarget;\n\n// optional inner split (used once after outer closure)\n// splitType = 0 none, 1 horizontal keep top, 2 vertical keep left\nbool didInnerSplit = false;\nbool innerActive = false;\nint splitType = 0;\nint splitPos = 0; // wall row or col\n\nbool inside(int x, int y) {\n    return 1 <= x && x <= B && 1 <= y && y <= B;\n}\n\nPos addDir(Pos p, char d) {\n    if (d == 'U' || d == 'u') --p.x;\n    else if (d == 'D' || d == 'd') ++p.x;\n    else if (d == 'L' || d == 'l') --p.y;\n    else if (d == 'R' || d == 'r') ++p.y;\n    return p;\n}\n\nPos transformPos(Pos p, int corner) {\n    if (corner == 0) return p;\n    if (corner == 1) return {p.x, B + 1 - p.y};\n    if (corner == 2) return {B + 1 - p.x, p.y};\n    return {B + 1 - p.x, B + 1 - p.y};\n}\n\nchar mapDirByCorner(char c, int corner) {\n    bool low = ('a' <= c && c <= 'z');\n    char d = (char)toupper(c);\n    if (corner == 1 || corner == 3) {\n        if (d == 'L') d = 'R';\n        else if (d == 'R') d = 'L';\n    }\n    if (corner == 2 || corner == 3) {\n        if (d == 'U') d = 'D';\n        else if (d == 'D') d = 'U';\n    }\n    if (low) d = (char)tolower(d);\n    return d;\n}\n\nint manhattan(Pos a, Pos b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<Pos> transformedVec(const vector<Pos>& src, int corner) {\n    vector<Pos> res = src;\n    for (auto& p : res) p = transformPos(p, corner);\n    return res;\n}\n\nbool canBuildCell(int tx, int ty, const vector<Pos>& hs, const vector<Pos>& ps) {\n    if (!inside(tx, ty)) return false;\n    if (wallg[tx][ty]) return false;\n    for (auto& h : hs) {\n        if (h.x == tx && h.y == ty) return false;\n    }\n    for (auto& p : ps) {\n        if (p.x == tx && p.y == ty) return false;\n        if (abs(p.x - tx) + abs(p.y - ty) == 1) return false;\n    }\n    return true;\n}\n\nchar bfsNextStep(Pos s, Pos t) {\n    if (s == t) return '.';\n    if (!inside(t.x, t.y) || wallg[t.x][t.y]) return '.';\n\n    static int dist[31][31];\n    for (int i = 1; i <= B; ++i) {\n        for (int j = 1; j <= B; ++j) dist[i][j] = -1;\n    }\n\n    queue<Pos> q;\n    q.push(t);\n    dist[t.x][t.y] = 0;\n\n    const char dirs[4] = {'U', 'D', 'L', 'R'};\n    while (!q.empty()) {\n        Pos cur = q.front(); q.pop();\n        for (char d : dirs) {\n            Pos nx = addDir(cur, d);\n            if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n            if (dist[nx.x][nx.y] != -1) continue;\n            dist[nx.x][nx.y] = dist[cur.x][cur.y] + 1;\n            q.push(nx);\n        }\n    }\n\n    int best = INF;\n    char ans = '.';\n    const char order[4] = {'U', 'L', 'R', 'D'};\n    for (char d : order) {\n        Pos nx = addDir(s, d);\n        if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n        if (dist[nx.x][nx.y] == -1) continue;\n        if (dist[nx.x][nx.y] < best) {\n            best = dist[nx.x][nx.y];\n            ans = d;\n        }\n    }\n    return ans;\n}\n\nbool allHumansInsideRect(const vector<Pos>& hs, int H, int W) {\n    for (auto& h : hs) {\n        if (h.x > H || h.y > W) return false;\n    }\n    return true;\n}\n\nint countPetsInsideRect(const vector<Pos>& ps, int H, int W) {\n    int c = 0;\n    for (auto& p : ps) if (p.x <= H && p.y <= W) ++c;\n    return c;\n}\n\nvoid computeParkTargets(int H, int W, const vector<Pos>& hs) {\n    vector<Pos> spots;\n    for (int sum = 2; sum <= H + W; ++sum) {\n        for (int x = 1; x <= H; ++x) {\n            int y = sum - x;\n            if (1 <= y && y <= W) {\n                if (x == H && y == W) continue;\n                spots.push_back({x, y});\n            }\n        }\n    }\n    if (spots.empty()) spots.push_back({1, 1});\n\n    parkTarget.assign(M, {1, 1});\n    vector<int> used(spots.size(), 0);\n    for (int i = 0; i < M; ++i) {\n        int best = -1, bestd = INF;\n        for (int k = 0; k < (int)spots.size(); ++k) if (!used[k]) {\n            int d = manhattan(hs[i], spots[k]);\n            if (d < bestd) {\n                bestd = d;\n                best = k;\n            }\n        }\n        if (best == -1) best = 0;\n        used[best] = 1;\n        parkTarget[i] = spots[best];\n    }\n}\n\nstruct Task {\n    Pos pos;   // human must stand here\n    Pos wall;  // then build this wall cell\n    char act;  // lowercase action\n};\n\n// ---------- outer enclosure helpers ----------\n\nPos outerDoorCell() {\n    if (keepDoorOuter == 0) return {outerH + 1, outerW};\n    return {outerH, outerW + 1};\n}\n\nchar outerDoorAct() {\n    return (keepDoorOuter == 0 ? 'd' : 'r');\n}\n\nbool allOuterWallsExceptDoorBuilt() {\n    if (keepDoorOuter == 0) {\n        for (int y = 1; y <= outerW - 1; ++y) if (!wallg[outerH + 1][y]) return false;\n        for (int x = 1; x <= outerH; ++x) if (!wallg[x][outerW + 1]) return false;\n    } else {\n        for (int y = 1; y <= outerW; ++y) if (!wallg[outerH + 1][y]) return false;\n        for (int x = 1; x <= outerH - 1; ++x) if (!wallg[x][outerW + 1]) return false;\n    }\n    return true;\n}\n\nbool outerFullyClosed() {\n    Pos d = outerDoorCell();\n    return allOuterWallsExceptDoorBuilt() && wallg[d.x][d.y];\n}\n\nvector<Task> getOuterBuildTasks() {\n    vector<Task> tasks;\n    if (keepDoorOuter == 0) {\n        for (int y = 1; y <= outerW - 1; ++y) {\n            if (!wallg[outerH + 1][y]) tasks.push_back({{outerH, y}, {outerH + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= outerH; ++x) {\n            if (!wallg[x][outerW + 1]) tasks.push_back({{x, outerW}, {x, outerW + 1}, 'r'});\n        }\n    } else {\n        for (int y = 1; y <= outerW; ++y) {\n            if (!wallg[outerH + 1][y]) tasks.push_back({{outerH, y}, {outerH + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= outerH - 1; ++x) {\n            if (!wallg[x][outerW + 1]) tasks.push_back({{x, outerW}, {x, outerW + 1}, 'r'});\n        }\n    }\n    return tasks;\n}\n\nPos outerCloserStand() {\n    if (keepDoorOuter == 0) return {outerH, outerW};\n    return {outerH, outerW};\n}\n\n// ---------- inner split helpers ----------\n\nint innerKeepH() {\n    if (splitType == 1) return splitPos - 1;\n    return curH;\n}\n\nint innerKeepW() {\n    if (splitType == 2) return splitPos - 1;\n    return curW;\n}\n\nPos innerDoorCell() {\n    if (splitType == 1) return {splitPos, curW};\n    return {curH, splitPos};\n}\n\nchar innerDoorAct() {\n    return (splitType == 1 ? 'd' : 'r');\n}\n\nPos innerCloserStand() {\n    if (splitType == 1) return {splitPos - 1, curW};\n    return {curH, splitPos - 1};\n}\n\nbool allInnerWallsExceptDoorBuilt() {\n    if (!innerActive) return true;\n    if (splitType == 1) {\n        for (int y = 1; y <= curW - 1; ++y) if (!wallg[splitPos][y]) return false;\n    } else {\n        for (int x = 1; x <= curH - 1; ++x) if (!wallg[x][splitPos]) return false;\n    }\n    return true;\n}\n\nbool innerFullyClosedNow() {\n    if (!innerActive) return false;\n    Pos d = innerDoorCell();\n    return allInnerWallsExceptDoorBuilt() && wallg[d.x][d.y];\n}\n\nbool allHumansInInnerSide(const vector<Pos>& hs) {\n    if (splitType == 1) {\n        for (auto& h : hs) if (h.x >= splitPos) return false;\n    } else {\n        for (auto& h : hs) if (h.y >= splitPos) return false;\n    }\n    return true;\n}\n\nint countPetsInInnerSide(const vector<Pos>& ps) {\n    int c = 0;\n    if (splitType == 1) {\n        for (auto& p : ps) if (p.x < splitPos && p.y <= curW) ++c;\n    } else {\n        for (auto& p : ps) if (p.y < splitPos && p.x <= curH) ++c;\n    }\n    return c;\n}\n\nvector<Task> getInnerBuildTasks() {\n    vector<Task> tasks;\n    if (splitType == 1) {\n        // horizontal line at row splitPos, keep top, leave door at y=curW\n        for (int y = 1; y <= curW - 1; ++y) {\n            if (!wallg[splitPos][y]) tasks.push_back({{splitPos - 1, y}, {splitPos, y}, 'd'});\n        }\n    } else {\n        // vertical line at col splitPos, keep left, leave door at x=curH\n        for (int x = 1; x <= curH - 1; ++x) {\n            if (!wallg[x][splitPos]) tasks.push_back({{x, splitPos - 1}, {x, splitPos}, 'r'});\n        }\n    }\n    return tasks;\n}\n\ndouble boundaryPressureOuter(const vector<Pos>& ps, int H, int W, int keepDoor) {\n    double s = 0.0;\n    for (auto& p : ps) {\n        // pressure near bottom wall\n        if (abs(p.x - (H + 1)) <= 1 && 1 <= p.y && p.y <= W) s += 2.0;\n        // pressure near right wall\n        if (abs(p.y - (W + 1)) <= 1 && 1 <= p.x && p.x <= H) s += 2.0;\n        // extra near door\n        Pos d = (keepDoor == 0 ? Pos{H + 1, W} : Pos{H, W + 1});\n        int md = manhattan(p, d);\n        if (md <= 8) s += (9 - md) * 0.7;\n    }\n    return s;\n}\n\nvoid chooseStrategy(const vector<Pos>& initPetsActual, const vector<Pos>& initHumansActual) {\n    double bestValue = -1e100;\n    int bestCorner = 0, bestH = 8, bestW = 8, bestKeep = 0;\n\n    for (int corner = 0; corner < 4; ++corner) {\n        auto tp = transformedVec(initPetsActual, corner);\n        auto th = transformedVec(initHumansActual, corner);\n\n        int occ[31][31] = {};\n        for (auto& p : tp) occ[p.x][p.y]++;\n\n        int pref[31][31] = {};\n        for (int i = 1; i <= B; ++i) {\n            for (int j = 1; j <= B; ++j) {\n                pref[i][j] = occ[i][j] + pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1];\n            }\n        }\n\n        for (int H = 4; H <= 18; ++H) {\n            for (int W = 4; W <= 18; ++W) {\n                int petCnt = pref[H][W];\n\n                int enterSum = 0, enterMax = 0;\n                for (auto& h : th) {\n                    int d = max(0, h.x - H) + max(0, h.y - W);\n                    enterSum += d;\n                    enterMax = max(enterMax, d);\n                }\n\n                for (int kd = 0; kd < 2; ++kd) {\n                    double press = boundaryPressureOuter(tp, H, W, kd);\n                    int buildCells = H + W - 1;\n                    double value =\n                        1.0 * H * W * pow(0.46, petCnt)\n                        - 0.46 * enterSum\n                        - 0.18 * enterMax\n                        - 0.18 * buildCells\n                        - 0.55 * press;\n\n                    if (petCnt == 0) value += 18.0;\n                    else if (petCnt == 1) value += 4.0;\n                    else value -= 2.0 * (petCnt - 1);\n\n                    if (value > bestValue) {\n                        bestValue = value;\n                        bestCorner = corner;\n                        bestH = H;\n                        bestW = W;\n                        bestKeep = kd;\n                    }\n                }\n            }\n        }\n    }\n\n    chosenCorner = bestCorner;\n    outerH = bestH;\n    outerW = bestW;\n    keepDoorOuter = bestKeep;\n    curH = outerH;\n    curW = outerW;\n\n    pets = transformedVec(initPetsActual, chosenCorner);\n    humans = transformedVec(initHumansActual, chosenCorner);\n\n    memset(wallg, 0, sizeof(wallg));\n    computeParkTargets(curH, curW, humans);\n}\n\n// returns true if activated\nbool tryActivateInnerSplit(const vector<Pos>& hs, const vector<Pos>& ps, int turn) {\n    if (didInnerSplit) return false;\n    if (!outerFullyClosed()) return false;\n    if (turn >= 265) return false;\n\n    int petsIn = countPetsInsideRect(ps, curH, curW);\n    if (petsIn == 0) return false;\n\n    double baseline = 1.0 * curH * curW * pow(0.5, petsIn);\n    double bestScore = baseline;\n    int bestType = 0, bestPos = 0;\n\n    // horizontal split: keep top\n    for (int x = 2; x <= curH; ++x) {\n        int keepH = x - 1;\n        int keepW = curW;\n        int petKeep = 0, linePress = 0, humanMove = 0;\n        for (auto& p : ps) {\n            if (p.x < x && p.y <= curW) ++petKeep;\n            if (abs(p.x - x) <= 1 && p.y <= curW) ++linePress;\n        }\n        for (auto& h : hs) {\n            if (h.x >= x && h.y <= curW) humanMove += (h.x - (x - 1));\n        }\n        if (petKeep >= petsIn) continue;\n        double score =\n            1.0 * keepH * keepW * pow(0.52, petKeep)\n            - 0.35 * curW\n            - 0.40 * humanMove\n            - 1.3 * linePress;\n        if (petKeep == 0) score += 6.0;\n        if (score > bestScore + 3.0) {\n            bestScore = score;\n            bestType = 1;\n            bestPos = x;\n        }\n    }\n\n    // vertical split: keep left\n    for (int y = 2; y <= curW; ++y) {\n        int keepH = curH;\n        int keepW = y - 1;\n        int petKeep = 0, linePress = 0, humanMove = 0;\n        for (auto& p : ps) {\n            if (p.y < y && p.x <= curH) ++petKeep;\n            if (abs(p.y - y) <= 1 && p.x <= curH) ++linePress;\n        }\n        for (auto& h : hs) {\n            if (h.y >= y && h.x <= curH) humanMove += (h.y - (y - 1));\n        }\n        if (petKeep >= petsIn) continue;\n        double score =\n            1.0 * keepH * keepW * pow(0.52, petKeep)\n            - 0.35 * curH\n            - 0.40 * humanMove\n            - 1.3 * linePress;\n        if (petKeep == 0) score += 6.0;\n        if (score > bestScore + 3.0) {\n            bestScore = score;\n            bestType = 2;\n            bestPos = y;\n        }\n    }\n\n    if (bestType == 0) return false;\n\n    didInnerSplit = true;\n    innerActive = true;\n    splitType = bestType;\n    splitPos = bestPos;\n    computeParkTargets(innerKeepH(), innerKeepW(), hs);\n    return true;\n}\n\nbool shouldCloseOuterDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 180 && petsInside <= 1) return true;\n    if (turn >= 230 && petsInside <= 2) return true;\n    if (turn >= 290 && petsInside <= 3) return true;\n    if (turn >= 297) return true;\n    return false;\n}\n\nbool shouldCloseInnerDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 250 && petsInside <= 1) return true;\n    if (turn >= 290 && petsInside <= 2) return true;\n    if (turn >= 297) return true;\n    return false;\n}\n\nint nearestHumanTo(Pos target, const vector<Pos>& hs) {\n    int id = 0, bd = INF;\n    for (int i = 0; i < (int)hs.size(); ++i) {\n        int d = manhattan(hs[i], target);\n        if (d < bd) {\n            bd = d;\n            id = i;\n        }\n    }\n    return id;\n}\n\nvoid assignBuildActions(const vector<Pos>& hs0, const vector<Pos>& ps0,\n                        const vector<Task>& tasks, Pos closerStand, int reserveCloser,\n                        vector<char>& act) {\n    vector<int> assignedTask(M, -1);\n    vector<int> usedTask(tasks.size(), 0);\n    vector<int> usedHuman(M, 0);\n\n    if (reserveCloser != -1) {\n        usedHuman[reserveCloser] = 1;\n        act[reserveCloser] = bfsNextStep(hs0[reserveCloser], closerStand);\n    }\n\n    // immediate builds first\n    for (int i = 0; i < M; ++i) {\n        if (usedHuman[i]) continue;\n        for (int t = 0; t < (int)tasks.size(); ++t) {\n            if (usedTask[t]) continue;\n            if (hs0[i] == tasks[t].pos &&\n                canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) {\n                assignedTask[i] = t;\n                usedTask[t] = 1;\n                usedHuman[i] = 1;\n                break;\n            }\n        }\n    }\n\n    struct Cand {\n        int d, i, t;\n        bool operator<(const Cand& o) const {\n            if (d != o.d) return d < o.d;\n            if (i != o.i) return i < o.i;\n            return t < o.t;\n        }\n    };\n    vector<Cand> cand;\n    for (int i = 0; i < M; ++i) if (!usedHuman[i]) {\n        for (int t = 0; t < (int)tasks.size(); ++t) if (!usedTask[t]) {\n            int d = manhattan(hs0[i], tasks[t].pos);\n            if (hs0[i] == tasks[t].pos &&\n                !canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) d += 3;\n            cand.push_back({d, i, t});\n        }\n    }\n    sort(cand.begin(), cand.end());\n    for (auto& c : cand) {\n        if (usedHuman[c.i] || usedTask[c.t]) continue;\n        usedHuman[c.i] = 1;\n        usedTask[c.t] = 1;\n        assignedTask[c.i] = c.t;\n    }\n\n    for (int i = 0; i < M; ++i) {\n        if (assignedTask[i] != -1) {\n            auto& task = tasks[assignedTask[i]];\n            if (hs0[i] == task.pos) {\n                if (canBuildCell(task.wall.x, task.wall.y, hs0, ps0)) act[i] = task.act;\n                else act[i] = '.';\n            } else {\n                act[i] = bfsNextStep(hs0[i], task.pos);\n            }\n        } else if (i != reserveCloser) {\n            act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<Pos> initPetsActual(N);\n    petType.resize(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> initPetsActual[i].x >> initPetsActual[i].y >> petType[i];\n    }\n\n    cin >> M;\n    vector<Pos> initHumansActual(M);\n    for (int i = 0; i < M; ++i) cin >> initHumansActual[i].x >> initHumansActual[i].y;\n\n    chooseStrategy(initPetsActual, initHumansActual);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<Pos> hs0 = humans;\n        vector<Pos> ps0 = pets;\n        vector<char> act(M, '.');\n\n        if (!outerFullyClosed()) {\n            if (!allOuterWallsExceptDoorBuilt()) {\n                vector<Task> tasks = getOuterBuildTasks();\n                int reserveCloser = -1;\n                if ((int)tasks.size() <= max(2, M / 3) || turn >= 220) {\n                    reserveCloser = nearestHumanTo(outerCloserStand(), hs0);\n                }\n                assignBuildActions(hs0, ps0, tasks, outerCloserStand(), reserveCloser, act);\n            } else {\n                Pos stand = outerCloserStand();\n                Pos door = outerDoorCell();\n                char doorAct = outerDoorAct();\n                int closer = nearestHumanTo(stand, hs0);\n\n                for (int i = 0; i < M; ++i) {\n                    if (i == closer) continue;\n                    act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                }\n\n                bool allIn = allHumansInsideRect(hs0, outerH, outerW);\n                int petsInside = countPetsInsideRect(ps0, outerH, outerW);\n                bool doClose = allIn && shouldCloseOuterDoor(turn, petsInside);\n\n                if (hs0[closer] != stand) {\n                    act[closer] = bfsNextStep(hs0[closer], stand);\n                } else {\n                    if (doClose && canBuildCell(door.x, door.y, hs0, ps0)) act[closer] = doorAct;\n                    else act[closer] = '.';\n                }\n            }\n        } else {\n            if (!innerActive) {\n                tryActivateInnerSplit(hs0, ps0, turn);\n            }\n\n            if (innerActive && !innerFullyClosedNow()) {\n                if (!allInnerWallsExceptDoorBuilt()) {\n                    vector<Task> tasks = getInnerBuildTasks();\n                    int reserveCloser = -1;\n                    if ((int)tasks.size() <= max(2, M / 3) || turn >= 275) {\n                        reserveCloser = nearestHumanTo(innerCloserStand(), hs0);\n                    }\n                    assignBuildActions(hs0, ps0, tasks, innerCloserStand(), reserveCloser, act);\n                } else {\n                    Pos stand = innerCloserStand();\n                    Pos door = innerDoorCell();\n                    char doorAct = innerDoorAct();\n                    int closer = nearestHumanTo(stand, hs0);\n\n                    for (int i = 0; i < M; ++i) {\n                        if (i == closer) continue;\n                        act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                    }\n\n                    bool allIn = allHumansInInnerSide(hs0);\n                    int petsInside = countPetsInInnerSide(ps0);\n                    bool doClose = allIn && shouldCloseInnerDoor(turn, petsInside);\n\n                    if (hs0[closer] != stand) {\n                        act[closer] = bfsNextStep(hs0[closer], stand);\n                    } else {\n                        if (doClose && canBuildCell(door.x, door.y, hs0, ps0)) act[closer] = doorAct;\n                        else act[closer] = '.';\n                    }\n                }\n            } else {\n                for (int i = 0; i < M; ++i) {\n                    act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                }\n            }\n        }\n\n        // sanitize build actions\n        set<pair<int,int>> buildSet;\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!canBuildCell(t.x, t.y, hs0, ps0)) {\n                    act[i] = '.';\n                    continue;\n                }\n                if (buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                    continue;\n                }\n                buildSet.insert({t.x, t.y});\n            }\n        }\n\n        // sanitize move actions\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!inside(t.x, t.y) || wallg[t.x][t.y] || buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        string out(M, '.');\n        for (int i = 0; i < M; ++i) out[i] = mapDirByCorner(act[i], chosenCorner);\n        cout << out << '\\n';\n        cout.flush();\n\n        // update walls\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (canBuildCell(t.x, t.y, hs0, ps0)) wallg[t.x][t.y] = true;\n            }\n        }\n\n        // update humans\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (inside(t.x, t.y) && !wallg[t.x][t.y] && !buildSet.count({t.x, t.y})) {\n                    humans[i] = t;\n                }\n            }\n        }\n\n        // if inner split just closed now, shrink current room\n        if (innerActive && innerFullyClosedNow()) {\n            curH = innerKeepH();\n            curW = innerKeepW();\n            innerActive = false;\n            computeParkTargets(curH, curW, humans);\n        }\n\n        // read pet moves\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                if (c == '.') continue;\n                char nc = mapDirByCorner(c, chosenCorner);\n                pets[i] = addDir(pets[i], nc);\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 = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr char DIRS[4] = {'U', 'D', 'L', 'R'};\n\nint si, sj, ti, tj;\ndouble P, Q;\nstring hwall[N];\nstring vwall[N - 1];\n\nint start_id, target_id;\nint nxtPos[V][4];\nint distToTarget[V];\n\ndouble adaptDP[MAXL + 2][V];\ndouble fwdDist[MAXL + 1][V];\n\ninline int id(int i, int j) { return i * N + j; }\ninline int r_of(int x) { return x / N; }\ninline int c_of(int x) { return x % N; }\n\ninline int dirIndex(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct State {\n    array<float, V> pr{};\n    array<char, MAXL> path{};\n    double score = 0.0;\n    double upper = 0.0;\n    double pri = 0.0;\n    int len = 0;\n};\n\nstring toString(const State& st) {\n    return string(st.path.begin(), st.path.begin() + st.len);\n}\n\nvoid buildTransitions() {\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int x = id(i, j);\n\n            // U\n            if (i == 0 || vwall[i - 1][j] == '1') nxtPos[x][0] = x;\n            else nxtPos[x][0] = id(i - 1, j);\n\n            // D\n            if (i == N - 1 || vwall[i][j] == '1') nxtPos[x][1] = x;\n            else nxtPos[x][1] = id(i + 1, j);\n\n            // L\n            if (j == 0 || hwall[i][j - 1] == '1') nxtPos[x][2] = x;\n            else nxtPos[x][2] = id(i, j - 1);\n\n            // R\n            if (j == N - 1 || hwall[i][j] == '1') nxtPos[x][3] = x;\n            else nxtPos[x][3] = id(i, j + 1);\n        }\n    }\n}\n\nvoid bfsTargetDist() {\n    fill(distToTarget, distToTarget + V, (int)1e9);\n    queue<int> q;\n    distToTarget[target_id] = 0;\n    q.push(target_id);\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        int d = distToTarget[x];\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (distToTarget[y] > d + 1) {\n                distToTarget[y] = d + 1;\n                q.push(y);\n            }\n        }\n    }\n}\n\n// Relaxation: from each exact cell, future actions may be chosen adaptively.\n// This is an upper bound for the real open-loop problem.\nvoid buildAdaptiveDP() {\n    for (int x = 0; x < V; x++) adaptDP[MAXL + 1][x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        for (int x = 0; x < V; x++) {\n            if (x == target_id) {\n                adaptDP[step][x] = 0.0;\n                continue;\n            }\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int y = nxtPos[x][a];\n                double val = P * adaptDP[step + 1][x];\n                if (y == target_id) val += Q * reward;\n                else val += Q * adaptDP[step + 1][y];\n                if (val > best) best = val;\n            }\n            adaptDP[step][x] = best;\n        }\n    }\n}\n\nState initialState() {\n    State st;\n    st.pr.fill(0.0f);\n    st.pr[start_id] = 1.0f;\n    st.score = 0.0;\n    st.len = 0;\n    st.upper = adaptDP[1][start_id];\n    st.pri = st.upper + 5.0;\n    return st;\n}\n\nState extendState(const State& st, int a, int step) {\n    State nx;\n    nx.pr.fill(0.0f);\n    nx.path = st.path;\n    nx.path[st.len] = DIRS[a];\n    nx.len = st.len + 1;\n    nx.score = st.score;\n\n    double reward = 401.0 - step;\n\n    for (int x = 0; x < V; x++) {\n        float q = st.pr[x];\n        if (q < 1e-8f) continue;\n\n        int y = nxtPos[x][a];\n        if (y == target_id) {\n            float stay = q * (float)P;\n            if (stay > 0) nx.pr[x] += stay;\n            nx.score += (double)q * Q * reward;\n        } else if (y == x) {\n            nx.pr[x] += q;\n        } else {\n            float stay = q * (float)P;\n            float go = q * (float)Q;\n            if (stay > 0) nx.pr[x] += stay;\n            if (go > 0) nx.pr[y] += go;\n        }\n    }\n\n    double future = 0.0;\n    double sq = 0.0;\n    int nextStep = step + 1;\n    for (int x = 0; x < V; x++) {\n        double p = nx.pr[x];\n        if (p < 1e-12) continue;\n        future += p * adaptDP[nextStep][x];\n        sq += p * p;\n    }\n    nx.upper = nx.score + future;\n    nx.pri = nx.upper + 6.0 * sq;\n    return nx;\n}\n\nState applyPrefixState(const string& s) {\n    State st = initialState();\n    for (int step = 1; step <= (int)s.size(); step++) {\n        st = extendState(st, dirIndex(s[step - 1]), step);\n    }\n    return st;\n}\n\nState greedyComplete(State cur, bool usePri) {\n    for (int step = cur.len + 1; step <= MAXL; step++) {\n        State best;\n        bool first = true;\n        for (int a = 0; a < 4; a++) {\n            State nx = extendState(cur, a, step);\n            double key = usePri ? nx.pri : nx.upper;\n            if (first) {\n                best = std::move(nx);\n                first = false;\n            } else {\n                double bkey = usePri ? best.pri : best.upper;\n                if (key > bkey + 1e-12 ||\n                    (fabs(key - bkey) <= 1e-12 && nx.score > best.score)) {\n                    best = std::move(nx);\n                }\n            }\n        }\n        cur = std::move(best);\n    }\n    return cur;\n}\n\nstring completeByGreedy(const string& prefix, bool usePri) {\n    string pref = prefix;\n    if ((int)pref.size() > MAXL) pref.resize(MAXL);\n    State st = applyPrefixState(pref);\n    if (st.len == MAXL) return pref;\n    State full = greedyComplete(st, usePri);\n    return toString(full);\n}\n\ndouble evaluateString(const string& s) {\n    static double cur[V], nxt[V];\n    fill(cur, cur + V, 0.0);\n    cur[start_id] = 1.0;\n    double score = 0.0;\n\n    for (int step = 1; step <= (int)s.size(); step++) {\n        fill(nxt, nxt + V, 0.0);\n        int a = dirIndex(s[step - 1]);\n        double reward = 401.0 - step;\n\n        for (int x = 0; x < V; x++) {\n            double q = cur[x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                nxt[x] += q * P;\n                score += q * Q * reward;\n            } else if (y == x) {\n                nxt[x] += q;\n            } else {\n                nxt[x] += q * P;\n                nxt[y] += q * Q;\n            }\n        }\n        memcpy(cur, nxt, sizeof(double) * V);\n    }\n    return score;\n}\n\nvoid computeForwardDist(const string& s) {\n    for (int x = 0; x < V; x++) fwdDist[0][x] = 0.0;\n    fwdDist[0][start_id] = 1.0;\n\n    for (int step = 1; step <= MAXL; step++) {\n        int a = dirIndex(s[step - 1]);\n        for (int x = 0; x < V; x++) fwdDist[step][x] = 0.0;\n\n        for (int x = 0; x < V; x++) {\n            double q = fwdDist[step - 1][x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                fwdDist[step][x] += q * P;\n            } else if (y == x) {\n                fwdDist[step][x] += q;\n            } else {\n                fwdDist[step][x] += q * P;\n                fwdDist[step][y] += q * Q;\n            }\n        }\n    }\n}\n\n// Build a new string by one exact right-to-left best-response pass.\n// The produced score is exact for the produced string.\ndouble backwardPassConstruct(const string& s, string& ns) {\n    computeForwardDist(s);\n    ns = s;\n\n    double valNext[V], valCur[V];\n    for (int x = 0; x < V; x++) valNext[x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        double bestScore = -1e100;\n        double bestHit = -1.0;\n        int bestA = 0;\n\n        for (int a = 0; a < 4; a++) {\n            double sc = 0.0;\n            double hit = 0.0;\n            for (int x = 0; x < V; x++) {\n                double pr = fwdDist[step - 1][x];\n                if (pr < 1e-14) continue;\n                int y = nxtPos[x][a];\n                double lv = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n                sc += pr * lv;\n                if (y == target_id) hit += pr * Q;\n            }\n            if (sc > bestScore + 1e-12 ||\n                (fabs(sc - bestScore) <= 1e-12 && hit > bestHit + 1e-15)) {\n                bestScore = sc;\n                bestHit = hit;\n                bestA = a;\n            }\n        }\n\n        ns[step - 1] = DIRS[bestA];\n        for (int x = 0; x < V; x++) {\n            int y = nxtPos[x][bestA];\n            valCur[x] = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n        }\n        memcpy(valNext, valCur, sizeof(double) * V);\n    }\n\n    return valNext[start_id];\n}\n\ndouble localOptimize(string& s, int maxPasses, double endTime,\n                     const function<double()>& elapsed) {\n    double curScore = evaluateString(s);\n    for (int pass = 0; pass < maxPasses && elapsed() < endTime; pass++) {\n        string ns;\n        double newScore = backwardPassConstruct(s, ns);\n        if (newScore > curScore + 1e-12) {\n            s.swap(ns);\n            curScore = newScore;\n        } else {\n            break;\n        }\n    }\n    return curScore;\n}\n\nstring routeByPenalties(double turnPenalty, double unsafeTurnPenalty) {\n    static const double INF = 1e100;\n    const int S = V * 5; // lastdir 0..3, 4 = none\n    vector<double> dist(S, INF);\n    vector<int> prevState(S, -1), prevMove(S, -1);\n\n    using PDI = pair<double, int>;\n    priority_queue<PDI, vector<PDI>, greater<PDI>> pq;\n\n    int st = start_id * 5 + 4;\n    dist[st] = 0.0;\n    pq.push({0.0, st});\n\n    while (!pq.empty()) {\n        auto [cd, sid] = pq.top();\n        pq.pop();\n        if (cd != dist[sid]) continue;\n\n        int x = sid / 5;\n        int last = sid % 5;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n\n            double w = 1.0;\n            if (last < 4 && last != a) {\n                w += turnPenalty;\n                if (nxtPos[x][last] != x) w += unsafeTurnPenalty;\n            }\n\n            int nsid = y * 5 + a;\n            double nd = cd + w;\n            if (nd + 1e-12 < dist[nsid]) {\n                dist[nsid] = nd;\n                prevState[nsid] = sid;\n                prevMove[nsid] = a;\n                pq.push({nd, nsid});\n            }\n        }\n    }\n\n    double best = INF;\n    int goal = -1;\n    for (int last = 0; last < 5; last++) {\n        int sid = target_id * 5 + last;\n        if (dist[sid] < best) {\n            best = dist[sid];\n            goal = sid;\n        }\n    }\n    if (goal == -1 || best >= INF / 2) return \"\";\n\n    string path;\n    int cur = goal;\n    while (cur != st) {\n        path.push_back(DIRS[prevMove[cur]]);\n        cur = prevState[cur];\n    }\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nstring randomShortestPath(double straightBias, double wallBias) {\n    string path;\n    int cur = start_id;\n    int prev = 4;\n\n    while (cur != target_id) {\n        vector<int> cand;\n        vector<double> w;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[cur][a];\n            if (y == cur) continue;\n            if (distToTarget[y] != distToTarget[cur] - 1) continue;\n\n            double ww = 1.0;\n            if (a == prev) ww *= straightBias;\n            if (nxtPos[y][a] == y) ww *= wallBias;\n            ww *= 0.9 + 0.2 * rng.nextDouble();\n\n            cand.push_back(a);\n            w.push_back(ww);\n        }\n\n        if (cand.empty()) break;\n\n        double sum = 0.0;\n        for (double x : w) sum += x;\n        double r = rng.nextDouble() * sum;\n        int choose = cand.back();\n        for (int i = 0; i < (int)cand.size(); i++) {\n            if ((r -= w[i]) <= 0) {\n                choose = cand[i];\n                break;\n            }\n        }\n        path.push_back(DIRS[choose]);\n        cur = nxtPos[cur][choose];\n        prev = choose;\n    }\n    return path;\n}\n\nstring makeTemplate(const string& path, int baseRep, int preTurnBonus, int postTurnBonus) {\n    string s;\n    for (int i = 0; i < (int)path.size() && (int)s.size() < MAXL; i++) {\n        int rep = baseRep;\n        if (i + 1 < (int)path.size() && path[i] != path[i + 1]) rep += preTurnBonus;\n        if (i > 0 && path[i - 1] != path[i]) rep += postTurnBonus;\n        for (int k = 0; k < rep && (int)s.size() < MAXL; k++) s.push_back(path[i]);\n    }\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> P;\n    Q = 1.0 - P;\n    for (int i = 0; i < N; i++) cin >> hwall[i];\n    for (int i = 0; i < N - 1; i++) cin >> vwall[i];\n\n    start_id = id(si, sj);\n    target_id = id(ti, tj);\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\n    buildTransitions();\n    bfsTargetDist();\n    buildAdaptiveDP();\n\n    double bestScore = -1.0;\n    string bestAns;\n    unordered_set<string> tried;\n\n    auto submitCandidate = [&](string s, int passes) {\n        if ((int)s.size() < MAXL) s = completeByGreedy(s, true);\n        if ((int)s.size() > MAXL) s.resize(MAXL);\n        if ((int)s.size() < MAXL) s += string(MAXL - s.size(), 'D');\n        if (!tried.insert(s).second) return;\n\n        double sc = localOptimize(s, passes, 1.95, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    };\n\n    // Baseline greedy completions\n    {\n        State init = initialState();\n        State g1 = greedyComplete(init, false);\n        submitCandidate(toString(g1), 6);\n\n        State g2 = greedyComplete(init, true);\n        submitCandidate(toString(g2), 6);\n    }\n\n    // Path-based candidates: explicitly diversify by turn / unsafe-turn penalties\n    vector<pair<double, double>> penaltyList = {\n        {0.0, 0.0},\n        {0.3, 0.0},\n        {0.8, 0.0},\n        {1.5, 0.0},\n        {0.4, 1.0},\n        {0.8, 2.0},\n        {1.2, 3.0},\n        {2.0, 4.0}\n    };\n\n    vector<string> paths;\n    for (auto [tp, up] : penaltyList) {\n        string path = routeByPenalties(tp, up);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Randomized shortest paths\n    for (int k = 0; k < 8; k++) {\n        double sb = 1.5 + 1.0 * rng.nextDouble();\n        double wb = 1.2 + 1.5 * rng.nextDouble();\n        string path = randomShortestPath(sb, wb);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Path templates\n    for (const string& path : paths) {\n        submitCandidate(path, 5);\n        submitCandidate(makeTemplate(path, 2, 0, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 1), 5);\n        submitCandidate(makeTemplate(path, 2, 1, 0), 5);\n        if (P >= 0.30) submitCandidate(makeTemplate(path, 3, 0, 0), 4);\n        if (P >= 0.35) submitCandidate(makeTemplate(path, 2, 1, 1), 4);\n    }\n\n    // Beam search with pruning by current best score\n    {\n        vector<State> beam, cand;\n        beam.reserve(500);\n        cand.reserve(2500);\n        beam.push_back(initialState());\n\n        auto cmpState = [](const State& a, const State& b) {\n            if (fabs(a.pri - b.pri) > 1e-12) return a.pri > b.pri;\n            if (fabs(a.upper - b.upper) > 1e-12) return a.upper > b.upper;\n            return a.score > b.score;\n        };\n\n        for (int step = 1; step <= MAXL; step++) {\n            if (elapsed() > 1.15) break;\n\n            int width;\n            if (step <= 40) width = 360;\n            else if (step <= 100) width = 280;\n            else width = 220;\n\n            cand.clear();\n            for (const State& st : beam) {\n                if (st.upper + 1e-12 < bestScore) continue;\n                for (int a = 0; a < 4; a++) {\n                    State nx = extendState(st, a, step);\n                    if (nx.upper + 1e-12 < bestScore) continue;\n                    cand.push_back(std::move(nx));\n                }\n            }\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(cand.begin(), cand.begin() + width, cand.end(), cmpState);\n                cand.resize(width);\n            }\n            sort(cand.begin(), cand.end(), cmpState);\n            beam.swap(cand);\n\n            if (!beam.empty() && (step <= 20 || step % 12 == 0)) {\n                int tries = min<int>(3, beam.size());\n                for (int i = 0; i < tries; i++) {\n                    string s1 = completeByGreedy(toString(beam[i]), true);\n                    submitCandidate(s1, 4);\n                    if (elapsed() > 1.20) break;\n                }\n            }\n        }\n\n        int tries = min<int>(8, beam.size());\n        for (int i = 0; i < tries && elapsed() < 1.35; i++) {\n            string s = completeByGreedy(toString(beam[i]), true);\n            submitCandidate(s, 5);\n        }\n    }\n\n    // Re-optimize best once more\n    if (!bestAns.empty() && elapsed() < 1.50) {\n        string s = bestAns;\n        double sc = localOptimize(s, 8, 1.60, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    // Random perturb + re-optimize\n    while (elapsed() < 1.96 && !bestAns.empty()) {\n        string s = bestAns;\n\n        int mode = rng.nextInt(0, 2);\n        if (mode == 0) {\n            int m = rng.nextInt(1, 3);\n            for (int t = 0; t < m; t++) {\n                int pos = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.8) * MAXL));\n                s[pos] = DIRS[rng.nextInt(0, 3)];\n            }\n        } else if (mode == 1) {\n            int l = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.7) * MAXL));\n            int len = rng.nextInt(2, 8);\n            char c = DIRS[rng.nextInt(0, 3)];\n            for (int i = l; i < min(MAXL, l + len); i++) s[i] = c;\n        } else {\n            int l = rng.nextInt(0, MAXL - 1);\n            int r = rng.nextInt(l, min(MAXL - 1, l + 10));\n            for (int i = l; i <= r; i++) s[i] = DIRS[rng.nextInt(0, 3)];\n        }\n\n        double sc = localOptimize(s, 3, 1.96, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    if (bestAns.empty()) {\n        State init = initialState();\n        State g = greedyComplete(init, true);\n        bestAns = toString(g);\n    }\n\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc010":"#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    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int CELLS = N * N;\nstatic constexpr int SIDES = CELLS * 4;\n\nstatic constexpr int di[4] = {0, -1, 0, 1};\nstatic constexpr int dj[4] = {-1, 0, 1, 0};\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int ROT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nstatic constexpr int PARTNER[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\nstruct Eval {\n    long long official = 0;\n    long long sumsq = 0;\n    int top1 = 0;\n    int top2 = 0;\n    int totalCycle = 0;\n    int loops = 0;\n    int broken = 0;\n    int conn = 0;\n};\n\nstruct Candidate {\n    array<uint8_t, CELLS> st{};\n    Eval ev;\n};\n\nstruct Solver {\n    array<string, N> input{};\n    array<uint8_t, CELLS> orig{};\n    uint8_t cand[CELLS][4]{};\n    uint8_t candCnt[CELLS]{};\n    int rotTo[8][8];\n    int mask[8];\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n    const double TIME_LIMIT = 1.95;\n\n    Solver() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng = XorShift64(seed);\n\n        memset(rotTo, -1, sizeof(rotTo));\n        for (int t = 0; t < 8; t++) {\n            int cur = t;\n            for (int k = 0; k < 4; k++) {\n                if (rotTo[t][cur] == -1) rotTo[t][cur] = k;\n                cur = ROT[cur];\n            }\n        }\n\n        for (int s = 0; s < 8; s++) {\n            int m = 0;\n            for (int d = 0; d < 4; d++) if (PARTNER[s][d] != -1) m |= (1 << d);\n            mask[s] = m;\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void read_input() {\n        for (int i = 0; i < N; i++) cin >> input[i];\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = input[i][j] - '0';\n                orig[p] = (uint8_t)t;\n                if (0 <= t && t <= 3) {\n                    candCnt[p] = 4;\n                    cand[p][0] = 0;\n                    cand[p][1] = 1;\n                    cand[p][2] = 2;\n                    cand[p][3] = 3;\n                } else if (t == 4 || t == 5) {\n                    candCnt[p] = 2;\n                    cand[p][0] = 4;\n                    cand[p][1] = 5;\n                } else {\n                    candCnt[p] = 2;\n                    cand[p][0] = 6;\n                    cand[p][1] = 7;\n                }\n            }\n        }\n    }\n\n    inline bool used(int s, int d) const {\n        return (mask[s] >> d) & 1;\n    }\n\n    inline uint8_t randCand(int pos) {\n        return cand[pos][rng.next_int(candCnt[pos])];\n    }\n\n    int localCellScore(const array<uint8_t, CELLS>& st, int pos, int ns) const {\n        int i = pos / N;\n        int j = pos % N;\n        int sc = 0;\n        int m = mask[ns];\n        for (int d = 0; d < 4; d++) {\n            bool u = (m >> d) & 1;\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (u) sc -= 3;\n            } else {\n                int np = ni * N + nj;\n                bool v = used(st[np], opp[d]);\n                if (u && v) sc += 2;\n                else if (u ^ v) sc -= 3;\n            }\n        }\n        return sc;\n    }\n\n    void localGreedy(array<uint8_t, CELLS>& st, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            bool changed = false;\n            for (int z = 0; z < CELLS; z++) {\n                int pos = order[z];\n                uint8_t cur = st[pos];\n                int bestSc = localCellScore(st, pos, cur);\n                uint8_t best = cur;\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == cur) continue;\n                    int sc = localCellScore(st, pos, ns);\n                    if (sc > bestSc || (sc == bestSc && rng.next_int(2) == 0)) {\n                        bestSc = sc;\n                        best = ns;\n                    }\n                }\n                if (best != cur) {\n                    st[pos] = best;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    Eval evaluate(const array<uint8_t, CELLS>& st) const {\n        Eval res;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int s = st[p];\n\n                if (j == 0 && used(s, 0)) { res.broken++; res.conn -= 3; }\n                if (i == 0 && used(s, 1)) { res.broken++; res.conn -= 3; }\n                if (j == N - 1 && used(s, 2)) { res.broken++; res.conn -= 3; }\n                if (i == N - 1 && used(s, 3)) { res.broken++; res.conn -= 3; }\n\n                if (j + 1 < N) {\n                    int q = i * N + (j + 1);\n                    bool a = used(st[p], 2);\n                    bool b = used(st[q], 0);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n                if (i + 1 < N) {\n                    int q = (i + 1) * N + j;\n                    bool a = used(st[p], 3);\n                    bool b = used(st[q], 1);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n            }\n        }\n\n        static uint8_t vis[SIDES];\n        static int stackv[SIDES];\n        memset(vis, 0, sizeof(vis));\n\n        for (int c = 0; c < CELLS; c++) {\n            int s = st[c];\n            for (int d = 0; d < 4; d++) {\n                if (!used(s, d)) continue;\n                int root = c * 4 + d;\n                if (vis[root]) continue;\n\n                int sp = 0;\n                stackv[sp++] = root;\n                vis[root] = 1;\n\n                int cnt = 0;\n                bool all2 = true;\n\n                while (sp) {\n                    int id = stackv[--sp];\n                    int cc = id >> 2;\n                    int dd = id & 3;\n                    int ss = st[cc];\n                    cnt++;\n\n                    int deg = 1;\n                    int i = cc / N;\n                    int j = cc % N;\n                    int ni = i + di[dd];\n                    int nj = j + dj[dd];\n                    bool ext = false;\n                    if (0 <= ni && ni < N && 0 <= nj && nj < N) {\n                        int nc = ni * N + nj;\n                        if (used(st[nc], opp[dd])) ext = true;\n                    }\n                    if (ext) deg++;\n                    if (deg != 2) all2 = false;\n\n                    int pd = PARTNER[ss][dd];\n                    int nid1 = cc * 4 + pd;\n                    if (!vis[nid1]) {\n                        vis[nid1] = 1;\n                        stackv[sp++] = nid1;\n                    }\n\n                    if (ext) {\n                        int nc = ni * N + nj;\n                        int nid2 = nc * 4 + opp[dd];\n                        if (!vis[nid2]) {\n                            vis[nid2] = 1;\n                            stackv[sp++] = nid2;\n                        }\n                    }\n                }\n\n                if (all2) {\n                    int len = cnt / 2;\n                    res.loops++;\n                    res.totalCycle += len;\n                    res.sumsq += 1LL * len * len;\n                    if (len > res.top1) {\n                        res.top2 = res.top1;\n                        res.top1 = len;\n                    } else if (len > res.top2) {\n                        res.top2 = len;\n                    }\n                }\n            }\n        }\n\n        if (res.loops >= 2) res.official = 1LL * res.top1 * res.top2;\n        else res.official = 0;\n        return res;\n    }\n\n    bool better(const Eval& a, const Eval& b) const {\n        if (a.official != b.official) return a.official > b.official;\n        if (a.top2 != b.top2) return a.top2 > b.top2;\n        if (a.top1 != b.top1) return a.top1 > b.top1;\n        if (a.sumsq != b.sumsq) return a.sumsq > b.sumsq;\n        if (a.totalCycle != b.totalCycle) return a.totalCycle > b.totalCycle;\n        if (a.conn != b.conn) return a.conn > b.conn;\n        if (a.broken != b.broken) return a.broken < b.broken;\n        return a.loops > b.loops;\n    }\n\n    array<uint8_t, CELLS> makeSeed(int mode) {\n        array<uint8_t, CELLS> st{};\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = orig[p];\n\n                if (mode == 0) {\n                    st[p] = orig[p];\n                } else if (mode == 1) {\n                    st[p] = randCand(p);\n                } else if (mode == 2) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 3) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 5 : 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 4) {\n                    if (t == 4 || t == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 5) {\n                    if (t == 4 || t == 5) st[p] = 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 6) {\n                    if (t == 6 || t == 7) st[p] = (j & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else if (mode == 7) {\n                    if (t == 6 || t == 7) st[p] = (i & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else if (mode == 8) {\n                    if (t == 4 || t == 5) st[p] = (i & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 9) {\n                    if (t == 4 || t == 5) st[p] = (j & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else {\n                    st[p] = randCand(p);\n                }\n            }\n        }\n        localGreedy(st, 6);\n        return st;\n    }\n\n    void exact1CellHill(array<uint8_t, CELLS>& st, Eval& cur, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            if (elapsed() > TIME_LIMIT) return;\n\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                if (elapsed() > TIME_LIMIT) return;\n\n                int pos = order[ii];\n                uint8_t old = st[pos];\n                uint8_t bestState = old;\n                Eval bestEv = cur;\n\n                int curLS = localCellScore(st, pos, old);\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == old) continue;\n\n                    int newLS = localCellScore(st, pos, ns);\n                    if (newLS + 10 < curLS) continue;\n\n                    st[pos] = ns;\n                    Eval ev = evaluate(st);\n                    if (better(ev, bestEv)) {\n                        bestEv = ev;\n                        bestState = ns;\n                    }\n                }\n\n                st[pos] = bestState;\n                if (bestState != old) {\n                    cur = bestEv;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool improveRandom2x2(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            int p[4] = {\n                i * N + j,\n                i * N + (j + 1),\n                (i + 1) * N + j,\n                (i + 1) * N + (j + 1)\n            };\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]], old3 = st[p[3]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2, b3 = old3;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        for (int d = 0; d < candCnt[p[3]]; d++) {\n                            st[p[3]] = cand[p[3]][d];\n                            Eval ev = evaluate(st);\n                            if (better(ev, bestEv)) {\n                                bestEv = ev;\n                                b0 = st[p[0]];\n                                b1 = st[p[1]];\n                                b2 = st[p[2]];\n                                b3 = st[p[3]];\n                            }\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n            st[p[3]] = b3;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n                st[p[3]] = old3;\n            }\n        }\n        return any;\n    }\n\n    bool improveRandomLine3(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            bool horizontal = rng.next_int(2) == 0;\n            int p[3];\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                p[0] = i * N + j;\n                p[1] = i * N + (j + 1);\n                p[2] = i * N + (j + 2);\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                p[0] = i * N + j;\n                p[1] = (i + 1) * N + j;\n                p[2] = (i + 2) * N + j;\n            }\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        Eval ev = evaluate(st);\n                        if (better(ev, bestEv)) {\n                            bestEv = ev;\n                            b0 = st[p[0]];\n                            b1 = st[p[1]];\n                            b2 = st[p[2]];\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n            }\n        }\n        return any;\n    }\n\n    bool improveRandomRect23(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            bool horizontal = rng.next_int(2) == 0;\n            vector<int> pos;\n            if (horizontal) {\n                int i = rng.next_int(N - 1);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 2; x++) for (int y = 0; y < 3; y++) pos.push_back((i + x) * N + (j + y));\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N - 1);\n                for (int x = 0; x < 3; x++) for (int y = 0; y < 2; y++) pos.push_back((i + x) * N + (j + y));\n            }\n\n            int prod = 1;\n            for (int p : pos) {\n                prod *= candCnt[p];\n                if (prod > 768) break;\n            }\n            if (prod > 768) continue;\n\n            array<uint8_t, 6> oldv{}, bestv{};\n            for (int i = 0; i < 6; i++) oldv[i] = bestv[i] = st[pos[i]];\n            Eval bestEv = cur;\n\n            function<void(int)> dfs = [&](int idx) {\n                if (elapsed() > TIME_LIMIT) return;\n                if (idx == 6) {\n                    Eval ev = evaluate(st);\n                    if (better(ev, bestEv)) {\n                        bestEv = ev;\n                        for (int i = 0; i < 6; i++) bestv[i] = st[pos[i]];\n                    }\n                    return;\n                }\n                int p = pos[idx];\n                for (int k = 0; k < candCnt[p]; k++) {\n                    st[p] = cand[p][k];\n                    dfs(idx + 1);\n                }\n            };\n\n            dfs(0);\n\n            for (int i = 0; i < 6; i++) st[pos[i]] = bestv[i];\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                for (int i = 0; i < 6; i++) st[pos[i]] = oldv[i];\n            }\n        }\n        return any;\n    }\n\n    void mutate(array<uint8_t, CELLS>& st) {\n        int style = rng.next_int(7);\n\n        if (style == 0) {\n            int k = 2 + rng.next_int(10);\n            for (int t = 0; t < k; t++) {\n                int p = rng.next_int(CELLS);\n                st[p] = randCand(p);\n            }\n        } else if (style == 1) {\n            int h = 2 + rng.next_int(4);\n            int w = 2 + rng.next_int(4);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    if (st[p] == 4) st[p] = 5;\n                    else if (st[p] == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                }\n            }\n        } else if (style == 2) {\n            int row = rng.next_int(N);\n            for (int j = 0; j < N; j++) {\n                int p = row * N + j;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 3) {\n            int col = rng.next_int(N);\n            for (int i = 0; i < N; i++) {\n                int p = i * N + col;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 4) {\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            for (int x = 0; x < 2; x++) for (int y = 0; y < 2; y++) {\n                int p = (i + x) * N + (j + y);\n                st[p] = randCand(p);\n            }\n        } else if (style == 5) {\n            bool horizontal = rng.next_int(2) == 0;\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 3; x++) st[i * N + (j + x)] = randCand(i * N + (j + x));\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                for (int x = 0; x < 3; x++) st[(i + x) * N + j] = randCand((i + x) * N + j);\n            }\n        } else {\n            bool horizontal = rng.next_int(2) == 0;\n            if (horizontal) {\n                int i = rng.next_int(N - 1);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 2; x++) for (int y = 0; y < 3; y++) {\n                    int p = (i + x) * N + (j + y);\n                    if ((st[p] == 4 || st[p] == 5) && rng.next_int(2)) st[p] = (st[p] == 4 ? 5 : 4);\n                    else st[p] = randCand(p);\n                }\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N - 1);\n                for (int x = 0; x < 3; x++) for (int y = 0; y < 2; y++) {\n                    int p = (i + x) * N + (j + y);\n                    if ((st[p] == 4 || st[p] == 5) && rng.next_int(2)) st[p] = (st[p] == 4 ? 5 : 4);\n                    else st[p] = randCand(p);\n                }\n            }\n        }\n    }\n\n    Candidate crossoverChild(const Candidate& A, const Candidate& B) {\n        Candidate c = A;\n        int style = rng.next_int(4);\n\n        if (style == 0) {\n            int h = 2 + rng.next_int(8);\n            int w = 2 + rng.next_int(8);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else if (style == 1) {\n            int si = rng.next_int(N);\n            int h = 1 + rng.next_int(N - si);\n            for (int i = si; i < si + h; i++) {\n                for (int j = 0; j < N; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else if (style == 2) {\n            int sj = rng.next_int(N);\n            int w = 1 + rng.next_int(N - sj);\n            for (int i = 0; i < N; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else {\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    if (((i + j) & 1) == 0) {\n                        int p = i * N + j;\n                        c.st[p] = B.st[p];\n                    }\n                }\n            }\n        }\n\n        localGreedy(c.st, 2);\n        c.ev = evaluate(c.st);\n        return c;\n    }\n\n    void addElite(vector<Candidate>& elite, const Candidate& c, int limit = 7) {\n        elite.push_back(c);\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n        if ((int)elite.size() > limit) elite.resize(limit);\n    }\n\n    string solve() {\n        start_time = chrono::steady_clock::now();\n        vector<Candidate> elite;\n\n        {\n            Candidate c;\n            c.st = orig;\n            c.ev = evaluate(c.st);\n            addElite(elite, c);\n        }\n\n        for (int mode = 0; mode <= 9; mode++) {\n            if (elapsed() > 0.35) break;\n            Candidate c;\n            c.st = makeSeed(mode);\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            improveRandomLine3(c.st, c.ev, 6);\n            improveRandom2x2(c.st, c.ev, 6);\n            improveRandomRect23(c.st, c.ev, 2);\n            addElite(elite, c);\n        }\n\n        while (elapsed() < 0.75) {\n            Candidate c;\n            c.st = makeSeed(1 + rng.next_int(10));\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            addElite(elite, c);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        for (int id = 0; id < (int)elite.size(); id++) {\n            if (elapsed() > 1.10) break;\n            exact1CellHill(elite[id].st, elite[id].ev, 1);\n            improveRandomLine3(elite[id].st, elite[id].ev, 10);\n            improveRandom2x2(elite[id].st, elite[id].ev, 10);\n            improveRandomRect23(elite[id].st, elite[id].ev, 3);\n            exact1CellHill(elite[id].st, elite[id].ev, 1);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        while (elapsed() < TIME_LIMIT) {\n            int mode = rng.next_int(100);\n            Candidate cur;\n\n            if (mode < 25 && (int)elite.size() >= 2) {\n                int a = rng.next_int((int)elite.size());\n                int b = rng.next_int((int)elite.size() - 1);\n                if (b >= a) b++;\n                cur = crossoverChild(elite[a], elite[b]);\n            } else {\n                int idx;\n                int r = rng.next_int(100);\n                if (r < 50) idx = 0;\n                else if (r < 75) idx = min<int>(1, (int)elite.size() - 1);\n                else idx = rng.next_int((int)elite.size());\n\n                cur = elite[idx];\n                mutate(cur.st);\n                localGreedy(cur.st, 2);\n                cur.ev = evaluate(cur.st);\n            }\n\n            exact1CellHill(cur.st, cur.ev, 1);\n            improveRandomLine3(cur.st, cur.ev, 6 + rng.next_int(6));\n            improveRandom2x2(cur.st, cur.ev, 6 + rng.next_int(6));\n            improveRandomRect23(cur.st, cur.ev, 1 + rng.next_int(3));\n\n            if (rng.next_int(100) < 35) {\n                exact1CellHill(cur.st, cur.ev, 1);\n            }\n\n            addElite(elite, cur);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        const auto& best = elite[0].st;\n        string ans;\n        ans.reserve(CELLS);\n        for (int p = 0; p < CELLS; p++) {\n            int t = orig[p];\n            int s = best[p];\n            int r = rotTo[t][s];\n            if (r < 0) r = 0;\n            ans.push_back(char('0' + r));\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXM = 100;\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\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 XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l));\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\nstatic inline char opposite(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    if (c == 'R') return 'L';\n    return 0;\n}\n\nstatic inline int move_index(char c) {\n    if (c == 0) return 0;\n    if (c == 'U') return 1;\n    if (c == 'D') return 2;\n    if (c == 'L') return 3;\n    return 4;\n}\n\nstatic inline int next_pos(int empty, char mv, int N) {\n    if (mv == 'U') return empty - N;\n    if (mv == 'D') return empty + N;\n    if (mv == 'L') return empty - 1;\n    return empty + 1;\n}\n\nstruct FastDepthTable {\n    static constexpr int LOG = 21;\n    static constexpr int SZ = 1 << LOG;\n    static constexpr int MASK = SZ - 1;\n\n    vector<uint64_t> key;\n    vector<uint16_t> dep;\n    vector<uint8_t> used;\n\n    FastDepthTable() : key(SZ), dep(SZ), used(SZ, 0) {}\n\n    inline bool prune(uint64_t k, int d) {\n        uint64_t h = splitmix64(k);\n        int idx = (int)(h & MASK);\n        while (true) {\n            if (!used[idx]) {\n                used[idx] = 1;\n                key[idx] = k;\n                dep[idx] = (uint16_t)d;\n                return false;\n            }\n            if (key[idx] == k) {\n                if ((int)dep[idx] < d) return true;\n                if ((int)dep[idx] > d) dep[idx] = (uint16_t)d;\n                return false;\n            }\n            idx = (idx + 1) & MASK;\n        }\n    }\n};\n\nstruct Metrics {\n    int largestTree = 0;\n    int largestCC = 0;\n    int largestCCCycles = 0;\n    int cycleExcess = 0;\n    int matchedEdges = 0;\n    int bestPotential = 0;\n    int components = 0;\n};\n\nstruct State {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Cand {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    uint64_t stateKey = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct BestRef {\n    bool isTemp = false;\n    int nodeIdx = 0;\n    int parent = -1;\n    char lastMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Elite {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    char prevMove = 0;\n    int depth = 0;\n    string prefix;\n    Metrics mt;\n};\n\nMetrics evaluateBoard(const array<uint8_t, MAXM>& board, int N) {\n    const int M = N * N;\n    static uint8_t deg[MAXM];\n    static uint8_t vis[MAXM];\n    static int adj[MAXM][4];\n    static int q[MAXM];\n\n    memset(deg, 0, M);\n    memset(vis, 0, M);\n\n    int matchedEdges = 0;\n\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 = board[id];\n            if (t == 0) continue;\n\n            if (c + 1 < N) {\n                int id2 = id + 1;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 4) && (u & 1)) {\n                    adj[id][deg[id]++] = id2;\n                    adj[id2][deg[id2]++] = id;\n                    matchedEdges++;\n                }\n            }\n            if (r + 1 < N) {\n                int id2 = id + N;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 8) && (u & 2)) {\n                    adj[id][deg[id]++] = id2;\n                    adj[id2][deg[id2]++] = id;\n                    matchedEdges++;\n                }\n            }\n        }\n    }\n\n    Metrics mt;\n    mt.matchedEdges = matchedEdges;\n\n    for (int s = 0; s < M; s++) {\n        if (board[s] == 0 || vis[s]) continue;\n        mt.components++;\n\n        int head = 0, tail = 0;\n        q[tail++] = s;\n        vis[s] = 1;\n\n        int v = 0;\n        int sumDeg = 0;\n\n        while (head < tail) {\n            int u = q[head++];\n            v++;\n            sumDeg += deg[u];\n            for (int k = 0; k < deg[u]; k++) {\n                int to = adj[u][k];\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        int e = sumDeg >> 1;\n        int cyc = max(0, e - v + 1);\n        mt.cycleExcess += cyc;\n        if (e == v - 1) mt.largestTree = max(mt.largestTree, v);\n        if (v > mt.largestCC || (v == mt.largestCC && cyc < mt.largestCCCycles)) {\n            mt.largestCC = v;\n            mt.largestCCCycles = cyc;\n        }\n        mt.bestPotential = max(mt.bestPotential, 4 * v - 7 * cyc);\n    }\n\n    return mt;\n}\n\nbool betterReal(const Metrics& a, int depthA, const Metrics& b, int depthB, int fullSize) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestTree == fullSize && depthA != depthB) return depthA < depthB;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.components != b.components) return a.components < b.components;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.largestCCCycles != b.largestCCCycles) return a.largestCCCycles < b.largestCCCycles;\n    if (a.bestPotential != b.bestPotential) return a.bestPotential > b.bestPotential;\n    return false;\n}\n\nlong long keyTree(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 55) {\n        return 1'000'000'000'000LL * m.bestPotential\n             +   10'000'000'000LL * m.largestCC\n             +      100'000'000LL * m.matchedEdges\n             -        2'000'000LL * m.largestCCCycles\n             -        1'000'000LL * m.components\n             +           10'000LL * m.largestTree\n             -              100LL * m.cycleExcess;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   10'000'000'000LL * m.matchedEdges\n             -      100'000'000LL * m.cycleExcess\n             -       10'000'000LL * m.components\n             +        1'000'000LL * m.largestCC\n             -           10'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nlong long keyMatch(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   10'000'000'000LL * m.cycleExcess\n         -      500'000'000LL * m.components\n         +      100'000'000LL * m.largestCC\n         -        1'000'000LL * m.largestCCCycles\n         +           10'000LL * m.largestTree\n         +                1LL * m.bestPotential;\n}\n\nlong long keyFocus(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   20'000'000'000LL * m.cycleExcess\n         -    1'000'000'000LL * m.components\n         +      500'000'000LL * m.largestTree\n         +       10'000'000LL * m.largestCC\n         -          100'000LL * m.largestCCCycles\n         +                1LL * m.bestPotential;\n}\n\nlong long keyDedup(const Metrics& m, int depth, int T) {\n    return max(keyTree(m, depth, T), keyMatch(m));\n}\n\nlong long keyRoll(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 75) {\n        return 1'000'000'000'000LL * m.matchedEdges\n             -   15'000'000'000LL * m.cycleExcess\n             -      800'000'000LL * m.components\n             +      200'000'000LL * m.largestCC\n             +      100'000'000LL * m.largestTree\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   20'000'000'000LL * m.matchedEdges\n             -   30'000'000'000LL * m.cycleExcess\n             -    2'000'000'000LL * m.components\n             +      100'000'000LL * m.largestCC\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nstring reconstructPathFromNode(const vector<State>& nodes, int idx) {\n    string s;\n    while (idx > 0) {\n        s.push_back(nodes[idx].prevMove);\n        idx = nodes[idx].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    cin >> N >> T;\n    int M = N * N;\n    int FULL = M - 1;\n\n    array<uint8_t, MAXM> initBoard{};\n    int initEmpty = -1;\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            initBoard[i * N + j] = (uint8_t)v;\n            if (v == 0) initEmpty = i * N + j;\n        }\n    }\n\n    uint64_t zob[MAXM][16];\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < MAXM; i++) {\n        for (int j = 0; j < 16; j++) {\n            seed = splitmix64(seed);\n            zob[i][j] = seed;\n        }\n    }\n    uint64_t pmSalt[5];\n    for (int i = 0; i < 5; i++) {\n        seed = splitmix64(seed);\n        pmSalt[i] = seed;\n    }\n    auto makeStateKey = [&](uint64_t hash, char prevMove) -> uint64_t {\n        return hash ^ pmSalt[move_index(prevMove)];\n    };\n\n    uint64_t initHash = 0;\n    for (int i = 0; i < M; i++) initHash ^= zob[i][initBoard[i]];\n\n    Timer timer;\n    XorShift64 rng(initHash ^ 0x9e3779b97f4a7c15ULL);\n\n    State root;\n    root.board = initBoard;\n    root.hash = initHash;\n    root.empty = initEmpty;\n    root.parent = -1;\n    root.prevMove = 0;\n    root.depth = 0;\n    root.mt = evaluateBoard(root.board, N);\n\n    if (root.mt.largestTree == FULL) {\n        cout << '\\n';\n        return 0;\n    }\n\n    int beamWidth1, beamWidth2;\n    double timeStage1, timeStage2, totalTimeLimit;\n\n    if (N <= 7) {\n        beamWidth1 = 360;\n        beamWidth2 = 100;\n        timeStage1 = 1.86;\n        timeStage2 = 2.48;\n        totalTimeLimit = 2.86;\n    } else if (N == 8) {\n        beamWidth1 = 305;\n        beamWidth2 = 84;\n        timeStage1 = 1.76;\n        timeStage2 = 2.40;\n        totalTimeLimit = 2.82;\n    } else if (N == 9) {\n        beamWidth1 = 250;\n        beamWidth2 = 70;\n        timeStage1 = 1.67;\n        timeStage2 = 2.32;\n        totalTimeLimit = 2.78;\n    } else {\n        beamWidth1 = 205;\n        beamWidth2 = 56;\n        timeStage1 = 1.58;\n        timeStage2 = 2.24;\n        totalTimeLimit = 2.74;\n    }\n\n    vector<State> nodes;\n    nodes.reserve(1 + (beamWidth1 + beamWidth2) * (T + 8));\n    nodes.push_back(root);\n\n    FastDepthTable globalSeen;\n    globalSeen.prune(makeStateKey(root.hash, root.prevMove), 0);\n\n    vector<int> cur, nxt;\n    cur.push_back(0);\n\n    BestRef best;\n    best.isTemp = false;\n    best.nodeIdx = 0;\n    best.depth = 0;\n    best.mt = root.mt;\n\n    const char moves[4] = {'U', 'D', 'L', 'R'};\n    int depth = 0;\n\n    auto materializeAnswer = [&](const BestRef& b) -> string {\n        string ans;\n        if (b.isTemp) {\n            ans = reconstructPathFromNode(nodes, b.parent);\n            ans.push_back(b.lastMove);\n        } else {\n            ans = reconstructPathFromNode(nodes, b.nodeIdx);\n        }\n        if ((int)ans.size() > T) ans.resize(T);\n        return ans;\n    };\n\n    auto makeEliteFromNode = [&](int idx) -> Elite {\n        Elite e;\n        const State& s = nodes[idx];\n        e.board = s.board;\n        e.hash = s.hash;\n        e.empty = s.empty;\n        e.prevMove = s.prevMove;\n        e.depth = s.depth;\n        e.prefix = reconstructPathFromNode(nodes, idx);\n        e.mt = s.mt;\n        return e;\n    };\n\n    auto makeEliteFromBestRef = [&](const BestRef& b) -> Elite {\n        if (!b.isTemp) return makeEliteFromNode(b.nodeIdx);\n        Elite e;\n        const State& p = nodes[b.parent];\n        e.board = p.board;\n        e.hash = p.hash;\n        e.empty = p.empty;\n        e.prevMove = b.lastMove;\n        e.prefix = reconstructPathFromNode(nodes, b.parent);\n        e.prefix.push_back(b.lastMove);\n        e.depth = (int)e.prefix.size();\n\n        int np = next_pos(p.empty, b.lastMove, N);\n        uint8_t tile = e.board[np];\n        e.board[p.empty] = tile;\n        e.board[np] = 0;\n        e.empty = np;\n        e.hash = p.hash ^ zob[p.empty][0] ^ zob[np][tile] ^ zob[p.empty][tile] ^ zob[np][0];\n        e.mt = b.mt;\n        return e;\n    };\n\n    auto tryUpdateBestTemp = [&](const Metrics& mt, int nd, int parent, char mv) {\n        if (betterReal(mt, nd, best.mt, best.depth, FULL)) {\n            best.isTemp = true;\n            best.parent = parent;\n            best.lastMove = mv;\n            best.depth = nd;\n            best.mt = mt;\n        }\n    };\n\n    auto tryUpdateBestNode = [&](int nodeIdx) {\n        const State& s = nodes[nodeIdx];\n        if (betterReal(s.mt, s.depth, best.mt, best.depth, FULL)) {\n            best.isTemp = false;\n            best.nodeIdx = nodeIdx;\n            best.depth = s.depth;\n            best.mt = s.mt;\n        }\n    };\n\n    // Stage 1\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage1) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool stopNow = false;\n        for (int ii = 0; ii < (int)cur.size(); ii++) {\n            if ((ii & 31) == 0 && timer.elapsed() > timeStage1) {\n                stopNow = true;\n                break;\n            }\n            int idx = cur[ii];\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                uint8_t tile = st.board[np];\n                uint64_t nh = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                uint64_t sk = makeStateKey(nh, mv);\n                int nd = st.depth + 1;\n\n                if (globalSeen.prune(sk, nd)) continue;\n\n                Cand cd;\n                cd.board = st.board;\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.depth = nd;\n                cd.hash = nh;\n                cd.stateKey = sk;\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, cd.depth, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    cout << materializeAnswer(best) << '\\n';\n                    return 0;\n                }\n\n                auto it = seen.find(sk);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(sk, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyDedup(cd.mt, cd.depth, T) > keyDedup(cands[pos].mt, cands[pos].depth, T)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n        }\n        if (stopNow && cands.empty()) break;\n        if (cands.empty()) break;\n\n        int C = (int)cands.size();\n        vector<int> ordA(C), ordB(C);\n        iota(ordA.begin(), ordA.end(), 0);\n        iota(ordB.begin(), ordB.end(), 0);\n\n        sort(ordA.begin(), ordA.end(), [&](int x, int y) {\n            long long kx = keyTree(cands[x].mt, cands[x].depth, T);\n            long long ky = keyTree(cands[y].mt, cands[y].depth, T);\n            if (kx != ky) return kx > ky;\n            return keyMatch(cands[x].mt) > keyMatch(cands[y].mt);\n        });\n        sort(ordB.begin(), ordB.end(), [&](int x, int y) {\n            long long kx = keyMatch(cands[x].mt);\n            long long ky = keyMatch(cands[y].mt);\n            if (kx != ky) return kx > ky;\n            return keyTree(cands[x].mt, cands[x].depth, T) > keyTree(cands[y].mt, cands[y].depth, T);\n        });\n\n        vector<char> picked(C, 0);\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 4;\n\n        nxt.clear();\n        nxt.reserve(min(C, beamWidth1));\n\n        int pa = 0, pb = 0;\n        while ((int)nxt.size() < beamWidth1 && (pa < C || pb < C)) {\n            bool progressed = false;\n\n            while (pa < C) {\n                int id = ordA[pa++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n                progressed = true;\n                break;\n            }\n            if ((int)nxt.size() >= beamWidth1) break;\n\n            while (pb < C) {\n                int id = ordB[pb++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n                progressed = true;\n                break;\n            }\n\n            if (!progressed) break;\n        }\n\n        if ((int)nxt.size() < beamWidth1) {\n            for (int t = 0; t < C && (int)nxt.size() < beamWidth1; t++) {\n                int id = ordA[t];\n                if (picked[id]) continue;\n                picked[id] = 1;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    if (best.mt.largestTree == FULL) {\n        cout << materializeAnswer(best) << '\\n';\n        return 0;\n    }\n\n    // Stage 2\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage2) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool stopNow = false;\n        for (int ii = 0; ii < (int)cur.size(); ii++) {\n            if ((ii & 31) == 0 && timer.elapsed() > timeStage2) {\n                stopNow = true;\n                break;\n            }\n            int idx = cur[ii];\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                uint8_t tile = st.board[np];\n                uint64_t nh = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                uint64_t sk = makeStateKey(nh, mv);\n                int nd = st.depth + 1;\n\n                if (globalSeen.prune(sk, nd)) continue;\n\n                Cand cd;\n                cd.board = st.board;\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.depth = nd;\n                cd.hash = nh;\n                cd.stateKey = sk;\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, cd.depth, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    cout << materializeAnswer(best) << '\\n';\n                    return 0;\n                }\n\n                auto it = seen.find(sk);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(sk, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyFocus(cd.mt) > keyFocus(cands[pos].mt)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n        }\n        if (stopNow && cands.empty()) break;\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b) {\n            long long ka = keyFocus(a.mt);\n            long long kb = keyFocus(b.mt);\n            if (ka != kb) return ka > kb;\n            return keyTree(a.mt, a.depth, T) > keyTree(b.mt, b.depth, T);\n        });\n\n        nxt.clear();\n        nxt.reserve(min((int)cands.size(), beamWidth2));\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 2;\n\n        for (auto& cd : cands) {\n            if ((int)nxt.size() >= beamWidth2) break;\n            if (emptyCnt[cd.empty] >= perEmptyLimit) continue;\n            emptyCnt[cd.empty]++;\n\n            State ns;\n            ns.board = cd.board;\n            ns.hash = cd.hash;\n            ns.empty = cd.empty;\n            ns.parent = cd.parent;\n            ns.prevMove = cd.prevMove;\n            ns.depth = cd.depth;\n            ns.mt = cd.mt;\n            int nid = (int)nodes.size();\n            nodes.push_back(std::move(ns));\n            nxt.push_back(nid);\n            tryUpdateBestNode(nid);\n        }\n\n        if (nxt.empty()) {\n            for (int i = 0; i < (int)cands.size() && (int)nxt.size() < beamWidth2; i++) {\n                State ns;\n                ns.board = cands[i].board;\n                ns.hash = cands[i].hash;\n                ns.empty = cands[i].empty;\n                ns.parent = cands[i].parent;\n                ns.prevMove = cands[i].prevMove;\n                ns.depth = cands[i].depth;\n                ns.mt = cands[i].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    string bestAns = materializeAnswer(best);\n    Metrics bestMt = best.mt;\n    int bestDepth = best.depth;\n\n    if (bestMt.largestTree == FULL || timer.elapsed() > totalTimeLimit - 0.04) {\n        if ((int)bestAns.size() > T) bestAns.resize(T);\n        cout << bestAns << '\\n';\n        return 0;\n    }\n\n    vector<Elite> elites;\n    {\n        vector<pair<long long, int>> ordF, ordT, ordM;\n        ordF.reserve(cur.size());\n        ordT.reserve(cur.size());\n        ordM.reserve(cur.size());\n\n        for (int idx : cur) {\n            ordF.push_back({keyFocus(nodes[idx].mt), idx});\n            ordT.push_back({keyTree(nodes[idx].mt, nodes[idx].depth, T), idx});\n            ordM.push_back({keyMatch(nodes[idx].mt), idx});\n        }\n        sort(ordF.begin(), ordF.end(), greater<>());\n        sort(ordT.begin(), ordT.end(), greater<>());\n        sort(ordM.begin(), ordM.end(), greater<>());\n\n        unordered_set<uint64_t> used;\n        used.reserve(32);\n\n        auto addNodeElite = [&](int idx) {\n            uint64_t k = makeStateKey(nodes[idx].hash, nodes[idx].prevMove);\n            if (used.insert(k).second) elites.push_back(makeEliteFromNode(idx));\n        };\n\n        for (int i = 0; i < min(4, (int)ordF.size()); i++) addNodeElite(ordF[i].second);\n        for (int i = 0; i < min(4, (int)ordT.size()); i++) addNodeElite(ordT[i].second);\n        for (int i = 0; i < min(3, (int)ordM.size()); i++) addNodeElite(ordM[i].second);\n\n        Elite eb = makeEliteFromBestRef(best);\n        if (used.insert(makeStateKey(eb.hash, eb.prevMove)).second) elites.push_back(std::move(eb));\n    }\n\n    struct Opt {\n        array<uint8_t, MAXM> board{};\n        uint64_t hash = 0;\n        int empty = 0;\n        char mv = 0;\n        Metrics mt;\n        long long key = 0;\n    };\n\n    auto eliteValue = [&](const Elite& e) {\n        return keyFocus(e.mt);\n    };\n\n    int rolloutTrials = 0;\n    int maxRolloutTrials = (N <= 7 ? 24 : (N == 8 ? 18 : (N == 9 ? 15 : 12)));\n\n    while (timer.elapsed() < totalTimeLimit && !elites.empty() && rolloutTrials < maxRolloutTrials) {\n        rolloutTrials++;\n\n        sort(elites.begin(), elites.end(), [&](const Elite& a, const Elite& b) {\n            return eliteValue(a) > eliteValue(b);\n        });\n\n        int pool = min(5, (int)elites.size());\n        int pickElite = rng.next_int(0, pool);\n        if ((rng.next() & 1ULL) == 0) pickElite = 0;\n\n        Elite base = elites[pickElite];\n\n        array<uint8_t, MAXM> board = base.board;\n        uint64_t hash = base.hash;\n        int empty = base.empty;\n        char prevMove = base.prevMove;\n        Metrics curMt = base.mt;\n        string suffix;\n        suffix.reserve(max(0, T - base.depth));\n\n        long long curKey = keyRoll(curMt, base.depth, T);\n        int stagnation = 0;\n        uint64_t recent[12];\n        int recentLen = 1, recentPos = 1;\n        recent[0] = makeStateKey(hash, prevMove);\n\n        int maxSuffix = min(T - base.depth, N <= 8 ? 48 : 36);\n\n        while ((int)suffix.size() < maxSuffix && base.depth + (int)suffix.size() < T && timer.elapsed() < totalTimeLimit) {\n            vector<Opt> opts;\n            opts.reserve(4);\n\n            int r = empty / N, c = empty % N;\n            for (char mv : moves) {\n                if (prevMove && mv == opposite(prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = empty - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = empty + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = empty - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = empty + 1;\n                }\n\n                Opt op;\n                op.board = board;\n                uint8_t tile = op.board[np];\n                op.board[empty] = tile;\n                op.board[np] = 0;\n                op.empty = np;\n                op.mv = mv;\n                op.hash = hash ^ zob[empty][0] ^ zob[np][tile] ^ zob[empty][tile] ^ zob[np][0];\n                op.mt = evaluateBoard(op.board, N);\n                op.key = keyRoll(op.mt, base.depth + (int)suffix.size() + 1, T);\n\n                uint64_t rk = makeStateKey(op.hash, mv);\n                for (int i = 0; i < recentLen; i++) {\n                    if (recent[i] == rk) {\n                        op.key -= 50'000'000LL;\n                        break;\n                    }\n                }\n                op.key += (long long)(rng.next() % 1001) - 500;\n                opts.push_back(std::move(op));\n            }\n\n            if (opts.empty()) break;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.key > b.key; });\n\n            int pick = 0;\n            if ((int)opts.size() >= 2) {\n                uint64_t rv = rng.next() % 100;\n                if (stagnation < 8) pick = (rv < 84 ? 0 : 1);\n                else pick = (rv < 62 ? 0 : 1);\n            }\n\n            Opt chosen = std::move(opts[pick]);\n            board = chosen.board;\n            hash = chosen.hash;\n            empty = chosen.empty;\n            prevMove = chosen.mv;\n            curMt = chosen.mt;\n            suffix.push_back(chosen.mv);\n\n            recent[recentPos % 12] = makeStateKey(hash, prevMove);\n            recentPos++;\n            if (recentLen < 12) recentLen++;\n\n            long long nk = keyRoll(curMt, base.depth + (int)suffix.size(), T);\n            if (nk > curKey) stagnation = 0;\n            else stagnation++;\n            curKey = nk;\n\n            int totalDepth = base.depth + (int)suffix.size();\n            if (betterReal(curMt, totalDepth, bestMt, bestDepth, FULL)) {\n                bestMt = curMt;\n                bestDepth = totalDepth;\n                bestAns = base.prefix + suffix;\n                if ((int)bestAns.size() > T) bestAns.resize(T);\n                if (bestMt.largestTree == FULL) {\n                    cout << bestAns << '\\n';\n                    return 0;\n                }\n            }\n\n            if (stagnation >= 14 && (int)suffix.size() >= 8) break;\n        }\n    }\n\n    if ((int)bestAns.size() > T) bestAns.resize(T);\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr double R = 10000.0;\nstatic constexpr int MAXK = 100;\n\nstruct Point {\n    int x, y;\n};\n\nstruct Part {\n    int m = 1;\n    vector<int> bin;\n    vector<long long> cuts; // A x + B y = C\n};\n\nstruct Sol {\n    int score = -1;\n    int goodCells = -1;\n    int A1 = 0, B1 = 1; // family 1 normal\n    int A2 = 1, B2 = 0; // family 2 normal\n    int m1 = 1, m2 = 1;\n    vector<long long> cuts1, cuts2;\n};\n\nstatic inline bool better_pair(int sc, int good, int bestSc, int bestGood) {\n    if (sc != bestSc) return sc > bestSc;\n    return good > bestGood;\n}\nstatic inline bool better_sol(const Sol& a, const Sol& b) {\n    return better_pair(a.score, a.goodCells, b.score, b.goodCells);\n}\n\npair<int,int> normalize_vec(int x, int y) {\n    if (x == 0 && y == 0) return {1, 0};\n    int g = std::gcd(abs(x), abs(y));\n    x /= g;\n    y /= g;\n    if (x < 0 || (x == 0 && y < 0)) {\n        x = -x;\n        y = -y;\n    }\n    return {x, y};\n}\n\nlong long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = 1; y = 0;\n        return a;\n    }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<long long,4> line_from_ABC(long long A, long long B, long long C) {\n    if (A == 0) {\n        long long y = C / B;\n        return {0, y, 1, y};\n    }\n    if (B == 0) {\n        long long x = C / A;\n        return {x, 0, x, 1};\n    }\n\n    long long x, y;\n    extgcd(llabs(A), llabs(B), x, y);\n    if (A < 0) x = -x;\n    if (B < 0) y = -y;\n\n    long long x0 = x * C;\n    long long y0 = y * C;\n\n    long double denom = (long double)A * A + (long double)B * B;\n    long double tt = ((long double)x0 * B - (long double)y0 * A) / denom;\n    long long t = llround(tt);\n\n    x0 -= B * t;\n    y0 += A * t;\n\n    long long x1 = x0, y1 = y0;\n    long long x2 = x0 - B, y2 = y0 + A;\n    return {x1, y1, x2, y2};\n}\n\nvector<double> select_lambdas(int N, const array<int,11>& a) {\n    vector<pair<double,double>> cand;\n    for (double lam = 0.8; lam <= 10.0 + 1e-9; lam += 0.2) {\n        double Mocc = N / lam;\n        double p = exp(-lam);\n        double score = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lam / d;\n            double bd = Mocc * p;\n            score += min<double>(a[d], bd);\n        }\n        cand.push_back({score, lam});\n    }\n    sort(cand.begin(), cand.end(), [&](auto &l, auto &r) {\n        return l.first > r.first;\n    });\n\n    vector<double> res;\n    for (auto [sc, lam] : cand) {\n        bool ok = true;\n        for (double x : res) {\n            if (abs(x - lam) < 0.35) { ok = false; break; }\n        }\n        if (ok) res.push_back(lam);\n        if ((int)res.size() >= 6) break;\n    }\n    if (res.empty()) res.push_back(5.0);\n    return res;\n}\n\nvector<pair<int,int>> generate_pairs(int N, int A, const array<int,11>& a, int cap = 84) {\n    const double PI = acos(-1.0);\n    vector<double> lambdas = select_lambdas(N, a);\n    set<pair<int,int>> st;\n\n    auto add_pair = [&](int m1, int m2) {\n        if (m1 < 1 || m2 < 1) return;\n        if (m1 + m2 - 2 > MAXK) return;\n        st.insert({m1, m2});\n    };\n\n    for (double lam : lambdas) {\n        double P = 4.0 * N / PI / lam;\n        vector<double> ratios = {1.0, 1.25, 1.4, 1.0 / 1.25, 1.0 / 1.4};\n\n        for (double ratio : ratios) {\n            int base1 = max(1, (int)llround(sqrt(P * ratio)));\n            for (int d1 = -2; d1 <= 2; d1++) {\n                int m1 = max(1, base1 + d1);\n                int base2 = max(1, (int)llround(P / m1));\n                for (int d2 = -2; d2 <= 2; d2++) {\n                    add_pair(m1, base2 + d2);\n                }\n            }\n        }\n    }\n\n    vector<int> oneD = {2,3,4,5,6,8,10,12,15,20,25,30,40,50,60,80,100};\n    for (int m : oneD) {\n        add_pair(1, m);\n        add_pair(m, 1);\n    }\n\n    {\n        double P = 4.0 * max(1, A) / PI;\n        int b = max(1, (int)llround(sqrt(P)));\n        for (int d1 = -4; d1 <= 4; d1++) {\n            int m1 = max(1, b + d1);\n            int m2 = max(1, (int)llround(P / m1));\n            for (int d2 = -3; d2 <= 3; d2++) add_pair(m1, m2 + d2);\n        }\n    }\n\n    vector<pair<int,int>> res(st.begin(), st.end());\n    sort(res.begin(), res.end(), [&](auto &L, auto &Rr) {\n        long long pL = 1LL * L.first * L.second;\n        long long pR = 1LL * Rr.first * Rr.second;\n        return pL > pR;\n    });\n    if ((int)res.size() > cap) res.resize(cap);\n    return res;\n}\n\nstruct PairSpec {\n    int A1, B1, A2, B2;\n};\n\nvector<PairSpec> generate_orth_specs() {\n    const double PI = acos(-1.0);\n    const int L = 997;\n    vector<PairSpec> res;\n    set<tuple<int,int,int,int>> used;\n\n    for (int i = 0; i < 30; i++) {\n        double ang = PI * i / 30.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        tie(dx, dy) = normalize_vec(dx, dy);\n\n        auto [A1, B1] = normalize_vec(-dy, dx);\n        auto [A2, B2] = normalize_vec(dx, dy);\n\n        auto key = make_tuple(A1, B1, A2, B2);\n        if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n    }\n\n    vector<pair<int,int>> extra_dirs = {\n        {1,0},{0,1},{1,1},{2,1},{1,2},{3,1},{1,3},{3,2},{2,3},{4,1},{1,4}\n    };\n    for (auto [dx0, dy0] : extra_dirs) {\n        auto [dx, dy] = normalize_vec(dx0, dy0);\n        auto [A1, B1] = normalize_vec(-dy, dx);\n        auto [A2, B2] = normalize_vec(dx, dy);\n        auto key = make_tuple(A1, B1, A2, B2);\n        if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n    }\n\n    return res;\n}\n\ndouble line_dir_angle_from_normal(int A, int B) {\n    return atan2((double)-A, (double)B);\n}\n\nvector<PairSpec> generate_near_specs(const Sol& s) {\n    const double PI = acos(-1.0);\n    const int L = 2003;\n    set<tuple<int,int,int,int>> used;\n    vector<PairSpec> res;\n\n    double a1 = line_dir_angle_from_normal(s.A1, s.B1);\n    double a2 = line_dir_angle_from_normal(s.A2, s.B2);\n\n    vector<double> da_list = {-4,-2,-1,0,1,2,4};\n    vector<double> db_list = {-15,0,15};\n\n    for (double da_deg : da_list) {\n        for (double db_deg : db_list) {\n            double ang1 = a1 + da_deg * M_PI / 180.0;\n            double ang2 = a2 + da_deg * M_PI / 180.0 + db_deg * M_PI / 180.0;\n\n            int dx1 = (int)llround(2003 * cos(ang1));\n            int dy1 = (int)llround(2003 * sin(ang1));\n            int dx2 = (int)llround(2003 * cos(ang2));\n            int dy2 = (int)llround(2003 * sin(ang2));\n\n            tie(dx1, dy1) = normalize_vec(dx1, dy1);\n            tie(dx2, dy2) = normalize_vec(dx2, dy2);\n\n            auto [A1, B1] = normalize_vec(-dy1, dx1);\n            auto [A2, B2] = normalize_vec(-dy2, dx2);\n\n            long long det = 1LL * A1 * B2 - 1LL * B1 * A2;\n            if (det == 0) continue;\n\n            auto key = make_tuple(A1, B1, A2, B2);\n            if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n        }\n    }\n\n    auto key = make_tuple(s.A1, s.B1, s.A2, s.B2);\n    if (used.insert(key).second) res.push_back({s.A1, s.B1, s.A2, s.B2});\n\n    return res;\n}\n\nstruct PairData {\n    int A1, B1, A2, B2;\n    double len1, len2;\n    long long lim1, lim2;\n    vector<long long> v1, v2;\n    vector<int> ord1, ord2;\n    vector<long long> s1, s2;\n    vector<char> feas1, feas2;\n    unordered_set<long long> forb1, forb2;\n};\n\nPairData prepare_pair(const vector<Point>& pts, const PairSpec& sp) {\n    PairData D;\n    D.A1 = sp.A1; D.B1 = sp.B1;\n    D.A2 = sp.A2; D.B2 = sp.B2;\n    D.len1 = hypot((double)D.A1, (double)D.B1);\n    D.len2 = hypot((double)D.A2, (double)D.B2);\n    D.lim1 = (long long)floor(R * D.len1 - 1e-7);\n    D.lim2 = (long long)floor(R * D.len2 - 1e-7);\n\n    int N = (int)pts.size();\n    D.v1.resize(N);\n    D.v2.resize(N);\n    D.ord1.resize(N);\n    D.ord2.resize(N);\n    D.forb1.reserve(N * 2 + 10);\n    D.forb2.reserve(N * 2 + 10);\n\n    for (int i = 0; i < N; i++) {\n        long long p1 = 1LL * D.A1 * pts[i].x + 1LL * D.B1 * pts[i].y;\n        long long p2 = 1LL * D.A2 * pts[i].x + 1LL * D.B2 * pts[i].y;\n        D.v1[i] = p1;\n        D.v2[i] = p2;\n        D.ord1[i] = i;\n        D.ord2[i] = i;\n        D.forb1.insert(p1);\n        D.forb2.insert(p2);\n    }\n\n    sort(D.ord1.begin(), D.ord1.end(), [&](int i, int j) {\n        if (D.v1[i] != D.v1[j]) return D.v1[i] < D.v1[j];\n        return i < j;\n    });\n    sort(D.ord2.begin(), D.ord2.end(), [&](int i, int j) {\n        if (D.v2[i] != D.v2[j]) return D.v2[i] < D.v2[j];\n        return i < j;\n    });\n\n    D.s1.resize(N);\n    D.s2.resize(N);\n    for (int i = 0; i < N; i++) {\n        D.s1[i] = D.v1[D.ord1[i]];\n        D.s2[i] = D.v2[D.ord2[i]];\n    }\n\n    D.feas1.assign(N + 1, 0);\n    D.feas2.assign(N + 1, 0);\n    for (int p = 1; p < N; p++) {\n        if (D.s1[p] - D.s1[p - 1] >= 2) D.feas1[p] = 1;\n        if (D.s2[p] - D.s2[p - 1] >= 2) D.feas2[p] = 1;\n    }\n\n    return D;\n}\n\nlong long adjust_constant(\n    long long target,\n    long long low,\n    long long high,\n    const unordered_set<long long>& forbidden\n) {\n    for (long long d = 0;; d++) {\n        long long c1 = target - d;\n        if (c1 >= low && c1 <= high && !forbidden.count(c1)) return c1;\n        if (d == 0) continue;\n        long long c2 = target + d;\n        if (c2 >= low && c2 <= high && !forbidden.count(c2)) return c2;\n    }\n}\n\nvoid build_bins_from_cuts(\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const vector<long long>& cuts,\n    vector<int>& bin\n) {\n    int N = (int)sortedVals.size();\n    bin.assign(N, 0);\n    int cur = 0, M = (int)cuts.size();\n    for (int r = 0; r < N; r++) {\n        while (cur < M && sortedVals[r] > cuts[cur]) cur++;\n        bin[ord[r]] = cur;\n    }\n}\n\nPart build_width_part(\n    int m,\n    double frac,\n    double len,\n    long long lim,\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const unordered_set<long long>& forbidden\n) {\n    Part part;\n    part.m = m;\n    int N = (int)sortedVals.size();\n\n    if (m == 1) {\n        part.bin.assign(N, 0);\n        return part;\n    }\n\n    double w = 2.0 * R / m;\n    vector<long long> cuts;\n    cuts.reserve(m - 1);\n\n    long long prev = -lim - 1;\n    for (int j = 0; j < m - 1; j++) {\n        double pos = -R + frac * w + j * w;\n        long long target = llround(pos * len);\n        long long c = adjust_constant(target, max(-lim + 1, prev + 1), lim - 1, forbidden);\n        cuts.push_back(c);\n        prev = c;\n    }\n\n    part.cuts = cuts;\n    build_bins_from_cuts(sortedVals, ord, cuts, part.bin);\n    return part;\n}\n\nbool same_sol(const Sol& a, const Sol& b) {\n    return a.A1 == b.A1 && a.B1 == b.B1 &&\n           a.A2 == b.A2 && a.B2 == b.B2 &&\n           a.m1 == b.m1 && a.m2 == b.m2 &&\n           a.cuts1 == b.cuts1 && a.cuts2 == b.cuts2;\n}\n\nvoid add_pool(vector<Sol>& pool, const Sol& cand, int limit) {\n    for (auto& x : pool) {\n        if (same_sol(x, cand)) {\n            if (better_sol(cand, x)) x = cand;\n            sort(pool.begin(), pool.end(), better_sol);\n            if ((int)pool.size() > limit) pool.resize(limit);\n            return;\n        }\n    }\n    pool.push_back(cand);\n    sort(pool.begin(), pool.end(), better_sol);\n    if ((int)pool.size() > limit) pool.resize(limit);\n}\n\nvoid try_eval_pair(\n    const Part& p1,\n    const Part& p2,\n    const PairSpec& sp,\n    const array<int,11>& a,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    static int cnt[105 * 105];\n    int cells = p1.m * p2.m;\n    for (int i = 0; i < cells; i++) cnt[i] = 0;\n\n    int N = (int)p1.bin.size();\n    for (int i = 0; i < N; i++) {\n        cnt[p1.bin[i] * p2.m + p2.bin[i]]++;\n    }\n\n    int hist[11] = {};\n    int good = 0;\n    for (int i = 0; i < cells; i++) {\n        int c = cnt[i];\n        if (1 <= c && c <= 10) {\n            hist[c]++;\n            good++;\n        }\n    }\n\n    int sc = 0;\n    for (int d = 1; d <= 10; d++) sc += min(a[d], hist[d]);\n\n    Sol cand;\n    cand.score = sc;\n    cand.goodCells = good;\n    cand.A1 = sp.A1; cand.B1 = sp.B1;\n    cand.A2 = sp.A2; cand.B2 = sp.B2;\n    cand.m1 = p1.m; cand.m2 = p2.m;\n    cand.cuts1 = p1.cuts;\n    cand.cuts2 = p2.cuts;\n\n    if (better_sol(cand, best)) best = cand;\n    if (pool) {\n        if ((int)pool->size() < poolLimit ||\n            better_pair(sc, good, pool->back().score, pool->back().goodCells)) {\n            add_pool(*pool, cand, poolLimit);\n        }\n    }\n}\n\nvoid search_with_specs(\n    const vector<Point>& pts,\n    const array<int,11>& a,\n    const vector<PairSpec>& specs,\n    const vector<pair<int,int>>& pairs,\n    const vector<double>& fracs,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    set<int> msset;\n    for (auto [m1, m2] : pairs) {\n        msset.insert(m1);\n        msset.insert(m2);\n    }\n    vector<int> ms(msset.begin(), msset.end());\n\n    for (const auto& sp : specs) {\n        PairData D = prepare_pair(pts, sp);\n        vector<vector<Part>> parts1(102), parts2(102);\n\n        for (int m : ms) {\n            if (m == 1) {\n                parts1[m].push_back(build_width_part(1, 0.5, D.len1, D.lim1, D.s1, D.ord1, D.forb1));\n                parts2[m].push_back(build_width_part(1, 0.5, D.len2, D.lim2, D.s2, D.ord2, D.forb2));\n            } else {\n                for (double f : fracs) {\n                    parts1[m].push_back(build_width_part(m, f, D.len1, D.lim1, D.s1, D.ord1, D.forb1));\n                    parts2[m].push_back(build_width_part(m, f, D.len2, D.lim2, D.s2, D.ord2, D.forb2));\n                }\n            }\n        }\n\n        for (auto [m1, m2] : pairs) {\n            for (const auto& p1 : parts1[m1]) {\n                for (const auto& p2 : parts2[m2]) {\n                    try_eval_pair(p1, p2, sp, a, best, pool, poolLimit);\n                }\n            }\n        }\n    }\n}\n\nstruct LocalOptimizer {\n    const PairData& D;\n    const array<int,11>& a;\n    int N, m1, m2;\n\n    vector<int> pos1, pos2;\n    vector<int> bin1, bin2;\n    vector<int> cnt;\n    int hist[11]{};\n    int score = 0;\n    int good = 0;\n\n    LocalOptimizer(const PairData& D_, const array<int,11>& a_, int m1_, int m2_)\n        : D(D_), a(a_), N((int)D_.s1.size()), m1(m1_), m2(m2_) {}\n\n    static vector<int> cuts_to_pos(const vector<long long>& sortedVals, const vector<long long>& cuts) {\n        vector<int> pos;\n        pos.reserve(cuts.size());\n        for (long long c : cuts) {\n            int p = upper_bound(sortedVals.begin(), sortedVals.end(), c) - sortedVals.begin();\n            pos.push_back(p);\n        }\n        return pos;\n    }\n\n    static bool strictly_increasing(const vector<int>& pos) {\n        for (int i = 1; i < (int)pos.size(); i++) if (pos[i] <= pos[i - 1]) return false;\n        return true;\n    }\n\n    static vector<long long> pos_to_cuts(const vector<long long>& sortedVals, const vector<int>& pos) {\n        vector<long long> cuts;\n        cuts.reserve(pos.size());\n        for (int p : pos) {\n            long long L = sortedVals[p - 1];\n            long long U = sortedVals[p];\n            long long c = (L + U) / 2;\n            if (c <= L) c = L + 1;\n            if (c >= U) c = U - 1;\n            cuts.push_back(c);\n        }\n        return cuts;\n    }\n\n    void build_bins_from_pos(const vector<int>& pos, const vector<int>& ord, vector<int>& bin) {\n        bin.assign(N, 0);\n        int cur = 0;\n        for (int r = 0; r < N; r++) {\n            while (cur < (int)pos.size() && r >= pos[cur]) cur++;\n            bin[ord[r]] = cur;\n        }\n    }\n\n    void rebuild_all() {\n        build_bins_from_pos(pos1, D.ord1, bin1);\n        build_bins_from_pos(pos2, D.ord2, bin2);\n\n        cnt.assign(m1 * m2, 0);\n        fill(hist, hist + 11, 0);\n        score = 0;\n        good = 0;\n\n        for (int i = 0; i < N; i++) {\n            cnt[bin1[i] * m2 + bin2[i]]++;\n        }\n        for (int v : cnt) {\n            if (1 <= v && v <= 10) {\n                hist[v]++;\n                good++;\n            }\n        }\n        for (int d = 1; d <= 10; d++) score += min(a[d], hist[d]);\n    }\n\n    bool valid_pos_family(const vector<int>& pos, const vector<char>& feas) const {\n        if (!strictly_increasing(pos)) return false;\n        for (int p : pos) {\n            if (!(1 <= p && p < N && feas[p])) return false;\n        }\n        return true;\n    }\n\n    bool init_from_positions(const vector<int>& p1, const vector<int>& p2) {\n        pos1 = p1;\n        pos2 = p2;\n        if (!valid_pos_family(pos1, D.feas1)) return false;\n        if (!valid_pos_family(pos2, D.feas2)) return false;\n        rebuild_all();\n        return true;\n    }\n\n    bool init_from_cuts(const vector<long long>& cuts1, const vector<long long>& cuts2) {\n        return init_from_positions(cuts_to_pos(D.s1, cuts1), cuts_to_pos(D.s2, cuts2));\n    }\n\n    inline void remove_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] - 1) - min(a[v], hist[v]);\n            hist[v]--;\n            good--;\n        }\n    }\n    inline void add_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] + 1) - min(a[v], hist[v]);\n            hist[v]++;\n            good++;\n        }\n    }\n    inline void modify_cell(int idx, int delta) {\n        int oldv = cnt[idx];\n        int newv = oldv + delta;\n        remove_hist(oldv);\n        cnt[idx] = newv;\n        add_hist(newv);\n    }\n\n    bool optimize_cut1(int j) {\n        int old = pos1[j];\n        int prv = (j == 0 ? 0 : pos1[j - 1]);\n        int nxt = (j + 1 == (int)pos1.size() ? N : pos1[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n            int p = r + 1;\n            if (p < nxt && D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n            int p = r;\n            if (D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell((j + 1) * m2 + b, -1);\n                modify_cell(j * m2 + b, +1);\n                bin1[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell(j * m2 + b, -1);\n                modify_cell((j + 1) * m2 + b, +1);\n                bin1[id]++;\n            }\n        }\n        pos1[j] = bestp;\n        return true;\n    }\n\n    bool optimize_cut2(int j) {\n        int old = pos2[j];\n        int prv = (j == 0 ? 0 : pos2[j - 1]);\n        int nxt = (j + 1 == (int)pos2.size() ? N : pos2[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n            int p = r + 1;\n            if (p < nxt && D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n            int p = r;\n            if (D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + (j + 1), -1);\n                modify_cell(b * m2 + j, +1);\n                bin2[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + j, -1);\n                modify_cell(b * m2 + (j + 1), +1);\n                bin2[id]++;\n            }\n        }\n        pos2[j] = bestp;\n        return true;\n    }\n\n    void optimize(int rounds = 10) {\n        for (int it = 0; it < rounds; it++) {\n            bool changed = false;\n            if (it % 2 == 0) {\n                for (int j = 0; j < (int)pos1.size(); j++) changed |= optimize_cut1(j);\n                for (int j = 0; j < (int)pos2.size(); j++) changed |= optimize_cut2(j);\n            } else {\n                for (int j = (int)pos2.size() - 1; j >= 0; j--) changed |= optimize_cut2(j);\n                for (int j = (int)pos1.size() - 1; j >= 0; j--) changed |= optimize_cut1(j);\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<long long> final_cuts1() const { return pos_to_cuts(D.s1, pos1); }\n    vector<long long> final_cuts2() const { return pos_to_cuts(D.s2, pos2); }\n};\n\nvector<Sol> pick_unique_geom_seeds(const vector<Sol>& pool, int limit) {\n    vector<Sol> res;\n    set<tuple<int,int,int,int,int,int>> used;\n    for (const auto& s : pool) {\n        auto key = make_tuple(s.A1, s.B1, s.A2, s.B2, s.m1, s.m2);\n        if (used.insert(key).second) {\n            res.push_back(s);\n            if ((int)res.size() >= limit) break;\n        }\n    }\n    return res;\n}\n\nvector<Sol> pick_top_exact(const vector<Sol>& pool, int limit) {\n    vector<Sol> res;\n    for (int i = 0; i < (int)pool.size() && i < limit; i++) res.push_back(pool[i]);\n    return res;\n}\n\nvector<Sol> merge_seed_lists(const vector<Sol>& A, const vector<Sol>& B, int limit) {\n    vector<Sol> res;\n    for (auto &s : A) add_pool(res, s, limit);\n    for (auto &s : B) add_pool(res, s, limit);\n    return res;\n}\n\nvector<int> build_quantile_pos(const vector<long long>& s, const vector<char>& feas, int m) {\n    int N = (int)s.size();\n    vector<int> fpos;\n    for (int p = 1; p < N; p++) if (feas[p]) fpos.push_back(p);\n    vector<int> pos;\n    if (m <= 1) return pos;\n    if ((int)fpos.size() < m - 1) return {};\n\n    int leftIdx = 0;\n    for (int j = 1; j <= m - 1; j++) {\n        int remain = (m - 1) - j;\n        int lo = leftIdx;\n        int hi = (int)fpos.size() - 1 - remain;\n        if (lo > hi) return {};\n\n        int target = (int)llround((long double)j * N / m);\n        int bestIndex = lo;\n        int bestDist = abs(fpos[lo] - target);\n\n        auto it = lower_bound(fpos.begin() + lo, fpos.begin() + hi + 1, target);\n        if (it != fpos.begin() + hi + 1) {\n            int idx = (int)(it - fpos.begin());\n            int dist = abs(fpos[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n        if (it != fpos.begin() + lo) {\n            int idx = (int)((it - fpos.begin()) - 1);\n            int dist = abs(fpos[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n\n        pos.push_back(fpos[bestIndex]);\n        leftIdx = bestIndex + 1;\n    }\n    return pos;\n}\n\nvector<vector<int>> generate_add_cut_candidates(const vector<int>& pos, const vector<char>& feas, int N, int maxCand = 2) {\n    vector<int> b;\n    b.reserve(pos.size() + 2);\n    b.push_back(0);\n    for (int p : pos) b.push_back(p);\n    b.push_back(N);\n\n    vector<pair<int, vector<int>>> cands;\n    for (int t = 0; t + 1 < (int)b.size(); t++) {\n        int l = b[t], r = b[t + 1];\n        if (r - l <= 1) continue;\n\n        int mid = (l + r) / 2;\n        int bestp = -1, bestDist = INT_MAX;\n        for (int p = max(l + 1, 1); p <= min(r - 1, N - 1); p++) {\n            if (!feas[p]) continue;\n            int dist = abs(p - mid);\n            if (dist < bestDist) {\n                bestDist = dist;\n                bestp = p;\n            }\n        }\n        if (bestp == -1) continue;\n\n        vector<int> np = pos;\n        np.insert(np.begin() + t, bestp);\n        cands.push_back({r - l, np});\n    }\n\n    sort(cands.begin(), cands.end(), [&](auto& L, auto& Rr) {\n        return L.first > Rr.first;\n    });\n\n    vector<vector<int>> res;\n    for (int i = 0; i < (int)cands.size() && i < maxCand; i++) res.push_back(cands[i].second);\n    return res;\n}\n\nvector<vector<int>> generate_remove_cut_candidates(const vector<int>& pos, int N, int maxCand = 2) {\n    vector<int> b;\n    b.reserve(pos.size() + 2);\n    b.push_back(0);\n    for (int p : pos) b.push_back(p);\n    b.push_back(N);\n\n    vector<pair<int, vector<int>>> cands;\n    for (int j = 0; j < (int)pos.size(); j++) {\n        int merged = b[j + 2] - b[j];\n        vector<int> np = pos;\n        np.erase(np.begin() + j);\n        cands.push_back({merged, np});\n    }\n\n    sort(cands.begin(), cands.end(), [&](auto& L, auto& Rr) {\n        return L.first < Rr.first;\n    });\n\n    vector<vector<int>> res;\n    for (int i = 0; i < (int)cands.size() && i < maxCand; i++) res.push_back(cands[i].second);\n    return res;\n}\n\nbool try_local_from_positions(\n    const PairData& D, const array<int,11>& a,\n    int m1, int m2,\n    const vector<int>& pos1, const vector<int>& pos2,\n    int rounds,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    LocalOptimizer opt(D, a, m1, m2);\n    if (!opt.init_from_positions(pos1, pos2)) return false;\n    opt.optimize(rounds);\n\n    Sol cand;\n    cand.score = opt.score;\n    cand.goodCells = opt.good;\n    cand.A1 = D.A1; cand.B1 = D.B1;\n    cand.A2 = D.A2; cand.B2 = D.B2;\n    cand.m1 = m1; cand.m2 = m2;\n    cand.cuts1 = opt.final_cuts1();\n    cand.cuts2 = opt.final_cuts2();\n\n    if (better_sol(cand, best)) best = cand;\n    if (pool) add_pool(*pool, cand, poolLimit);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n\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 A = 0;\n    for (int d = 1; d <= 10; d++) A += a[d];\n\n    Sol best;\n    vector<Sol> pool;\n\n    // 1) Coarse orthogonal search\n    auto coarseSpecs = generate_orth_specs();\n    auto coarsePairs = generate_pairs(N, A, a, 84);\n    vector<double> coarseFracs = {0.25, 0.5, 0.75};\n    search_with_specs(pts, a, coarseSpecs, coarsePairs, coarseFracs, best, &pool, 30);\n\n    // 2) Refine around several seeds, including slight skewness\n    {\n        auto seeds = pick_unique_geom_seeds(pool, 5);\n        vector<double> fineFracs = {0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875};\n\n        for (const auto& sd : seeds) {\n            auto nearSpecs = generate_near_specs(sd);\n            vector<pair<int,int>> nearPairs;\n            for (int m1 = max(1, sd.m1 - 2); m1 <= min(101, sd.m1 + 2); m1++) {\n                for (int m2 = max(1, sd.m2 - 2); m2 <= min(101, sd.m2 + 2); m2++) {\n                    if (m1 + m2 - 2 <= MAXK) nearPairs.push_back({m1, m2});\n                }\n            }\n            search_with_specs(pts, a, nearSpecs, nearPairs, fineFracs, best, &pool, 42);\n        }\n    }\n\n    // 3) Local optimization on many seeds\n    {\n        auto topSeeds = pick_top_exact(pool, 14);\n        auto uniqSeeds = pick_unique_geom_seeds(pool, 12);\n        auto localSeeds = merge_seed_lists(topSeeds, uniqSeeds, 22);\n\n        for (const auto& sd : localSeeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n            LocalOptimizer opt(D, a, sd.m1, sd.m2);\n            if (!opt.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n            opt.optimize(10);\n\n            Sol cand = sd;\n            cand.score = opt.score;\n            cand.goodCells = opt.good;\n            cand.cuts1 = opt.final_cuts1();\n            cand.cuts2 = opt.final_cuts2();\n\n            if (better_sol(cand, best)) best = cand;\n            add_pool(pool, cand, 42);\n        }\n    }\n\n    // 4) Quantile-based alternative seeds for top few geometries\n    {\n        auto seeds = pick_unique_geom_seeds(pool, 6);\n        for (const auto& sd : seeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n\n            vector<int> q1 = build_quantile_pos(D.s1, D.feas1, sd.m1);\n            vector<int> q2 = build_quantile_pos(D.s2, D.feas2, sd.m2);\n\n            if ((!q1.empty() || sd.m1 == 1) && (!q2.empty() || sd.m2 == 1)) {\n                try_local_from_positions(D, a, sd.m1, sd.m2, q1, q2, 10, best, &pool, 42);\n            }\n\n            LocalOptimizer tmp(D, a, sd.m1, sd.m2);\n            if (tmp.init_from_cuts(sd.cuts1, sd.cuts2)) {\n                if (!q1.empty() || sd.m1 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, q1, tmp.pos2, 8, best, &pool, 42);\n                }\n                if (!q2.empty() || sd.m2 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, tmp.pos1, q2, 8, best, &pool, 42);\n                }\n            }\n        }\n    }\n\n    // 5) Structural neighborhood: change (m1,m2) by \u00b11 around top seeds\n    {\n        auto topSeeds = pick_top_exact(pool, 8);\n        auto uniqSeeds = pick_unique_geom_seeds(pool, 8);\n        auto structSeeds = merge_seed_lists(topSeeds, uniqSeeds, 10);\n\n        for (const auto& sd : structSeeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n            LocalOptimizer base(D, a, sd.m1, sd.m2);\n            if (!base.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n\n            // m1 + 1\n            if (sd.m1 + sd.m2 - 1 <= MAXK) {\n                auto cands = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                for (auto& np1 : cands) {\n                    try_local_from_positions(D, a, sd.m1 + 1, sd.m2, np1, base.pos2, 8, best, &pool, 42);\n                }\n            }\n            // m1 - 1\n            if (sd.m1 >= 2) {\n                auto cands = generate_remove_cut_candidates(base.pos1, N, 2);\n                for (auto& np1 : cands) {\n                    try_local_from_positions(D, a, sd.m1 - 1, sd.m2, np1, base.pos2, 8, best, &pool, 42);\n                }\n            }\n            // m2 + 1\n            if (sd.m1 + sd.m2 - 1 <= MAXK) {\n                auto cands = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                for (auto& np2 : cands) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2 + 1, base.pos1, np2, 8, best, &pool, 42);\n                }\n            }\n            // m2 - 1\n            if (sd.m2 >= 2) {\n                auto cands = generate_remove_cut_candidates(base.pos2, N, 2);\n                for (auto& np2 : cands) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2 - 1, base.pos1, np2, 8, best, &pool, 42);\n                }\n            }\n\n            // NEW: transfer one cut from family2 to family1\n            if (sd.m2 >= 2) {\n                auto add1 = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                auto rem2 = generate_remove_cut_candidates(base.pos2, N, 2);\n                for (auto& np1 : add1) {\n                    for (auto& np2 : rem2) {\n                        try_local_from_positions(D, a, sd.m1 + 1, sd.m2 - 1, np1, np2, 8, best, &pool, 42);\n                    }\n                }\n            }\n\n            // NEW: transfer one cut from family1 to family2\n            if (sd.m1 >= 2) {\n                auto rem1 = generate_remove_cut_candidates(base.pos1, N, 2);\n                auto add2 = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                for (auto& np1 : rem1) {\n                    for (auto& np2 : add2) {\n                        try_local_from_positions(D, a, sd.m1 - 1, sd.m2 + 1, np1, np2, 8, best, &pool, 42);\n                    }\n                }\n            }\n        }\n    }\n\n    // 6) Final re-local-optimization on current best\n    {\n        PairSpec sp{best.A1, best.B1, best.A2, best.B2};\n        PairData D = prepare_pair(pts, sp);\n        LocalOptimizer opt(D, a, best.m1, best.m2);\n        if (opt.init_from_cuts(best.cuts1, best.cuts2)) {\n            opt.optimize(14);\n            Sol cand = best;\n            cand.score = opt.score;\n            cand.goodCells = opt.good;\n            cand.cuts1 = opt.final_cuts1();\n            cand.cuts2 = opt.final_cuts2();\n            if (better_sol(cand, best)) best = cand;\n        }\n    }\n\n    vector<array<long long,4>> out;\n    out.reserve(best.cuts1.size() + best.cuts2.size());\n\n    for (long long c : best.cuts1) out.push_back(line_from_ABC(best.A1, best.B1, c));\n    for (long long c : best.cuts2) out.push_back(line_from_ABC(best.A2, best.B2, c));\n\n    if ((int)out.size() > K) out.resize(K);\n\n    cout << out.size() << '\\n';\n    for (auto &ln : out) {\n        cout << ln[0] << ' ' << ln[1] << ' ' << ln[2] << ' ' << ln[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int INF_PERIM = 1e9;\n\nusing Op = array<int, 8>;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : 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    double next_double() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\nstruct Cand {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n    int gain;\n    int perim;\n    int area;\n    int longSide;\n    double eval;\n};\n\nstruct EvalParams {\n    double beta;\n    double gamma;\n    double adjBonus;\n    double pairBonus;\n    double longPenalty;\n    int topKeep;\n    int pickTop;\n    double bias;\n    int maxPerim;\n};\n\nstruct Strategy {\n    vector<int> caps;\n    double betaHi, betaLo;\n    double gammaHi, gammaLo;\n    double adjHi, adjLo;\n    double pairHi, pairLo;\n    double longHi, longLo;\n    int topKeep;\n    int pickTop;\n    double bias;\n    bool quotaMode;   // false: exhaust current cap first, true: progress by move count\n    int stageLen;     // used only if quotaMode\n};\n\nstruct State {\n    int N = 0;\n    int dotCount = 0;\n    uint8_t dot[MAXN][MAXN]{};\n    uint8_t H[MAXN][MAXN]{};   // (x,y)-(x+1,y)\n    uint8_t V[MAXN][MAXN]{};   // (x,y)-(x,y+1)\n    uint8_t D1[MAXN][MAXN]{};  // (x,y)-(x+1,y+1)\n    uint8_t D2[MAXN][MAXN]{};  // (x,y+1)-(x+1,y)\n    long long sumW = 0;\n    vector<Op> ops;\n};\n\nint N, M;\nint W[MAXN][MAXN];\nvector<int> cellOrder;\n\nint eastA[MAXN][MAXN], westA[MAXN][MAXN], northA[MAXN][MAXN], southA[MAXN][MAXN];\nint neA[MAXN][MAXN], nwA[MAXN][MAXN], seA[MAXN][MAXN], swA[MAXN][MAXN];\n\ninline int enc(int x, int y) { return (x << 6) | y; }\ninline int decx(int v) { return v >> 6; }\ninline int decy(int v) { return v & 63; }\ninline bool inside(int x, int y) { return 0 <= x && x < N && 0 <= y && y < N; }\ninline int sgn(int x) { return (x > 0) - (x < 0); }\n\ninline bool segment_used(const State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) return st.H[min(x1, x2)][y1];\n    if (x1 == x2) return st.V[x1][min(y1, y2)];\n    if ((x2 - x1) == (y2 - y1)) return st.D1[min(x1, x2)][min(y1, y2)];\n    return st.D2[min(x1, x2)][min(y1, y2)];\n}\n\ninline void mark_segment(State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        st.H[min(x1, x2)][y1] = 1;\n    } else if (x1 == x2) {\n        st.V[x1][min(y1, y2)] = 1;\n    } else if ((x2 - x1) == (y2 - y1)) {\n        st.D1[min(x1, x2)][min(y1, y2)] = 1;\n    } else {\n        st.D2[min(x1, x2)][min(y1, y2)] = 1;\n    }\n}\n\ninline bool check_edge(const State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    if (len <= 0) return false;\n\n    int x = x1, y = y1;\n    for (int i = 1; i < len; i++) {\n        x += dx;\n        y += dy;\n        if (st.dot[x][y]) return false;\n    }\n\n    x = x1;\n    y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        if (segment_used(st, x, y, nx, ny)) return false;\n        x = nx;\n        y = ny;\n    }\n    return true;\n}\n\ninline void mark_edge(State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    int x = x1, y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        mark_segment(st, x, y, nx, ny);\n        x = nx;\n        y = ny;\n    }\n}\n\ninline bool valid_rect(const State& st, const Cand& c) {\n    if (st.dot[c.x1][c.y1]) return false;\n    if (!st.dot[c.x2][c.y2] || !st.dot[c.x3][c.y3] || !st.dot[c.x4][c.y4]) return false;\n\n    if (!check_edge(st, c.x1, c.y1, c.x2, c.y2)) return false;\n    if (!check_edge(st, c.x2, c.y2, c.x3, c.y3)) return false;\n    if (!check_edge(st, c.x3, c.y3, c.x4, c.y4)) return false;\n    if (!check_edge(st, c.x4, c.y4, c.x1, c.y1)) return false;\n    return true;\n}\n\ninline void apply_move(State& st, const Cand& c) {\n    st.dot[c.x1][c.y1] = 1;\n    st.dotCount++;\n    st.sumW += W[c.x1][c.y1];\n\n    mark_edge(st, c.x1, c.y1, c.x2, c.y2);\n    mark_edge(st, c.x2, c.y2, c.x3, c.y3);\n    mark_edge(st, c.x3, c.y3, c.x4, c.y4);\n    mark_edge(st, c.x4, c.y4, c.x1, c.y1);\n\n    st.ops.push_back({c.x1, c.y1, c.x2, c.y2, c.x3, c.y3, c.x4, c.y4});\n}\n\ninline void push_top(vector<Cand>& best, const Cand& c, int K) {\n    if ((int)best.size() < K) {\n        best.push_back(c);\n        int i = (int)best.size() - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    } else if (c.eval > best.back().eval) {\n        best.back() = c;\n        int i = K - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    }\n}\n\ninline int adjacent_count8(const State& st, int x, int y) {\n    int cnt = 0;\n    for (int dx = -1; dx <= 1; dx++) {\n        int nx = x + dx;\n        if (nx < 0 || nx >= N) continue;\n        for (int dy = -1; dy <= 1; dy++) {\n            int ny = y + dy;\n            if (dx == 0 && dy == 0) continue;\n            if (ny < 0 || ny >= N) continue;\n            cnt += st.dot[nx][ny];\n        }\n    }\n    return cnt;\n}\n\nvoid build_nearest(const State& st) {\n    for (int y = 0; y < N; y++) {\n        int last = -1;\n        for (int x = 0; x < N; x++) {\n            westA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int x = N - 1; x >= 0; x--) {\n            eastA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        int last = -1;\n        for (int y = 0; y < N; y++) {\n            southA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int y = N - 1; y >= 0; y--) {\n            northA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            swA[x][y] = (x == 0 || y == 0) ? -1\n                : (st.dot[x - 1][y - 1] ? enc(x - 1, y - 1) : swA[x - 1][y - 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = N - 1; y >= 0; y--) {\n            neA[x][y] = (x == N - 1 || y == N - 1) ? -1\n                : (st.dot[x + 1][y + 1] ? enc(x + 1, y + 1) : neA[x + 1][y + 1]);\n        }\n    }\n    for (int x = 0; x < N; x++) {\n        for (int y = N - 1; y >= 0; y--) {\n            nwA[x][y] = (x == 0 || y == N - 1) ? -1\n                : (st.dot[x - 1][y + 1] ? enc(x - 1, y + 1) : nwA[x - 1][y + 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = 0; y < N; y++) {\n            seA[x][y] = (x == N - 1 || y == 0) ? -1\n                : (st.dot[x + 1][y - 1] ? enc(x + 1, y - 1) : seA[x + 1][y - 1]);\n        }\n    }\n}\n\nvector<Cand> collect_top_candidates(const State& st, const EvalParams& prm) {\n    build_nearest(st);\n\n    vector<Cand> best;\n    best.reserve(prm.topKeep);\n\n    const double maxAdjBonus = max(0.0, prm.adjBonus) * 8.0;\n    const double maxPairBonus = max(0.0, prm.pairBonus) * 8.0;\n    const double minPenalty = max(0.0, prm.beta) * 4.0 + max(0.0, prm.gamma) * 1.0;\n    // longPenalty term is 0 for the smallest possible rectangle (side length 1),\n    // so it is not included in this safe upper bound.\n\n    auto try_add = [&](int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4,\n                       int adj, int pairCnt) {\n        if (!inside(x3, y3)) return;\n        if (!st.dot[x3][y3]) return;\n\n        int l1 = max(abs(x2 - x1), abs(y2 - y1));\n        int l2 = max(abs(x4 - x1), abs(y4 - y1));\n        if (l1 <= 0 || l2 <= 0) return;\n\n        Cand c;\n        c.x1 = x1; c.y1 = y1;\n        c.x2 = x2; c.y2 = y2;\n        c.x3 = x3; c.y3 = y3;\n        c.x4 = x4; c.y4 = y4;\n        c.gain = W[x1][y1];\n        c.perim = 2 * (l1 + l2);\n        c.area = l1 * l2;\n        c.longSide = max(l1, l2);\n        if (c.perim > prm.maxPerim) return;\n\n        c.eval = c.gain\n               + prm.adjBonus * adj\n               + prm.pairBonus * pairCnt\n               - prm.beta * c.perim\n               - prm.gamma * c.area\n               - prm.longPenalty * (c.longSide - 1);\n\n        if (valid_rect(st, c)) push_top(best, c, prm.topKeep);\n    };\n\n    for (int id : cellOrder) {\n        int x = decx(id), y = decy(id);\n        if (st.dot[x][y]) continue;\n\n        if ((int)best.size() == prm.topKeep) {\n            double ub = W[x][y] + maxAdjBonus + maxPairBonus - minPenalty;\n            if (ub <= best.back().eval) break;\n        }\n\n        int e = eastA[x][y], w = westA[x][y], n = northA[x][y], s = southA[x][y];\n        int ne = neA[x][y], nw = nwA[x][y], se = seA[x][y], sw = swA[x][y];\n\n        int pairCnt = 0;\n        pairCnt += (e  != -1 && n  != -1);\n        pairCnt += (e  != -1 && s  != -1);\n        pairCnt += (w  != -1 && n  != -1);\n        pairCnt += (w  != -1 && s  != -1);\n        pairCnt += (ne != -1 && nw != -1);\n        pairCnt += (ne != -1 && se != -1);\n        pairCnt += (sw != -1 && nw != -1);\n        pairCnt += (sw != -1 && se != -1);\n\n        if (pairCnt == 0) continue;\n\n        int adj = adjacent_count8(st, x, y);\n\n        // Axis-aligned\n        if (e != -1 && n != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (e != -1 && s != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (w != -1 && n != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (w != -1 && s != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n\n        // 45-degree\n        if (ne != -1 && nw != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (ne != -1 && se != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (sw != -1 && nw != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (sw != -1 && se != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n    }\n\n    return best;\n}\n\nint choose_idx(const vector<Cand>& cand, int pickTop, double bias, XorShift64& rng) {\n    if (cand.empty()) return -1;\n    int m = min((int)cand.size(), pickTop);\n    if (m <= 1) return 0;\n    double r = rng.next_double();\n    int idx = (int)(pow(r, bias) * m);\n    if (idx >= m) idx = m - 1;\n    return idx;\n}\n\nState run_strategy(const State& initial, Strategy stg, XorShift64& rng,\n                   const function<double()>& elapsed, double TL, bool perturb) {\n    State st = initial;\n    st.ops.clear();\n    st.ops.reserve(N * N);\n\n    if (perturb) {\n        auto pert = [&](double v, double lo, double hi) {\n            return v * (lo + (hi - lo) * rng.next_double());\n        };\n        stg.betaHi = pert(stg.betaHi, 0.92, 1.08);\n        stg.betaLo = pert(stg.betaLo, 0.92, 1.08);\n        stg.gammaHi = pert(stg.gammaHi, 0.92, 1.08);\n        stg.gammaLo = pert(stg.gammaLo, 0.92, 1.08);\n        stg.adjHi = pert(stg.adjHi, 0.88, 1.12);\n        stg.adjLo = pert(stg.adjLo, 0.88, 1.12);\n        stg.pairHi = pert(stg.pairHi, 0.88, 1.12);\n        stg.pairLo = pert(stg.pairLo, 0.88, 1.12);\n        stg.longHi = pert(stg.longHi, 0.88, 1.12);\n        stg.longLo = pert(stg.longLo, 0.88, 1.12);\n        stg.bias = max(1.0, pert(stg.bias, 0.92, 1.08));\n        stg.pickTop = max(1, min(stg.topKeep, stg.pickTop + (int)(rng.next_u32() % 3) - 1));\n        if (stg.quotaMode) {\n            stg.stageLen = max(2, stg.stageLen + (int)(rng.next_u32() % 3) - 1);\n        }\n    }\n\n    int stage = 0;\n    int movesMade = 0;\n\n    while (elapsed() < TL) {\n        double prog = double(st.dotCount - M) / max(1, N * N - M);\n\n        EvalParams prm;\n        prm.beta = stg.betaHi * (1.0 - prog) + stg.betaLo * prog;\n        prm.gamma = stg.gammaHi * (1.0 - prog) + stg.gammaLo * prog;\n        prm.adjBonus = stg.adjHi * (1.0 - prog) + stg.adjLo * prog;\n        prm.pairBonus = stg.pairHi * (1.0 - prog) + stg.pairLo * prog;\n        prm.longPenalty = stg.longHi * (1.0 - prog) + stg.longLo * prog;\n        prm.topKeep = stg.topKeep;\n        prm.pickTop = stg.pickTop;\n        prm.bias = stg.bias;\n\n        vector<Cand> cand;\n\n        if (stg.quotaMode) {\n            int baseStage = min((int)stg.caps.size() - 1, movesMade / stg.stageLen);\n            bool found = false;\n            for (int s = baseStage; s < (int)stg.caps.size(); s++) {\n                prm.maxPerim = stg.caps[s];\n                cand = collect_top_candidates(st, prm);\n                if (!cand.empty()) {\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        } else {\n            if (stage >= (int)stg.caps.size()) stage = (int)stg.caps.size() - 1;\n            prm.maxPerim = stg.caps[stage];\n            cand = collect_top_candidates(st, prm);\n            if (cand.empty()) {\n                if (stage + 1 < (int)stg.caps.size()) {\n                    stage++;\n                    continue;\n                } else {\n                    break;\n                }\n            }\n        }\n\n        int idx = choose_idx(cand, prm.pickTop, prm.bias, rng);\n        apply_move(st, cand[idx]);\n        movesMade++;\n    }\n\n    return st;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State initial;\n    initial.N = N;\n\n    vector<pair<int, int>> initPts;\n    initPts.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        initial.dot[x][y] = 1;\n        initial.dotCount++;\n        initPts.push_back({x, y});\n    }\n\n    int c = (N - 1) / 2;\n    cellOrder.clear();\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            W[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n            cellOrder.push_back(enc(x, y));\n        }\n    }\n    sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n        int xa = decx(a), ya = decy(a);\n        int xb = decx(b), yb = decy(b);\n        if (W[xa][ya] != W[xb][yb]) return W[xa][ya] > W[xb][yb];\n        if (xa != xb) return xa < xb;\n        return ya < yb;\n    });\n\n    initial.sumW = 0;\n    for (auto [x, y] : initPts) initial.sumW += W[x][y];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    for (auto [x, y] : initPts) {\n        seed ^= (uint64_t)(x * 131 + y * 10007 + 17) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n    XorShift64 rng(seed);\n\n    int extra = (N >= 49 ? 4 : (N >= 41 ? 2 : 0));\n\n    vector<Strategy> strategies = {\n        // Small-first, anti-long strong\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.20, 0.18, 0.18, 0.020, 2.4, 0.4, 1.2, 0.1, 1.4, 0.1, 56 + extra, 5, 2.8, false, 0},\n        {{8, 12, 16, 24, INF_PERIM},    0.95, 0.12, 0.12, 0.010, 2.0, 0.2, 0.9, 0.1, 1.0, 0.1, 52 + extra, 4, 2.5, false, 0},\n        {{10, 14, 20, INF_PERIM},       0.70, 0.08, 0.08, 0.008, 1.4, 0.1, 0.7, 0.0, 0.7, 0.0, 44 + extra, 4, 2.2, false, 0},\n\n        // Balanced\n        {{INF_PERIM},                   0.45, 0.03, 0.040, 0.002, 0.8, 0.0, 0.5, 0.0, 0.3, 0.0, 40 + extra, 3, 2.0, false, 0},\n        {{18, 28, INF_PERIM},           0.35, 0.01, 0.020, 0.000, 0.5, 0.0, 0.4, 0.0, 0.4, 0.0, 40 + extra, 2, 1.7, false, 0},\n        {{INF_PERIM},                   0.18, 0.00, 0.010, 0.000, 0.2, 0.0, 0.2, 0.0, 0.1, 0.0, 32 + extra, 1, 1.0, false, 0},\n\n        // Quota/progress-based\n        {{8, 12, 16, 24, INF_PERIM},    1.00, 0.10, 0.12, 0.010, 1.8, 0.2, 0.8, 0.1, 0.9, 0.1, 48 + extra, 4, 2.3, true, 7},\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.30, 0.16, 0.20, 0.018, 2.2, 0.3, 1.0, 0.1, 1.2, 0.1, 56 + extra, 5, 2.7, true, 6},\n        {{10, 14, 20, INF_PERIM},       0.75, 0.06, 0.08, 0.006, 1.2, 0.1, 0.6, 0.0, 0.5, 0.0, 40 + extra, 3, 2.0, true, 8},\n\n        // Pair-potential-focused variants\n        {{8, 12, 16, INF_PERIM},        0.90, 0.10, 0.10, 0.008, 1.6, 0.1, 1.6, 0.2, 0.8, 0.1, 52 + extra, 4, 2.4, false, 0},\n        {{INF_PERIM},                   0.30, 0.01, 0.020, 0.000, 0.4, 0.0, 0.8, 0.0, 0.2, 0.0, 40 + extra, 2, 1.6, false, 0},\n\n        // More conservative against long blocking\n        {{6, 8, 10, 12, INF_PERIM},     1.10, 0.14, 0.14, 0.012, 2.0, 0.2, 0.9, 0.1, 1.8, 0.2, 52 + extra, 4, 2.6, false, 0},\n        {{12, 18, INF_PERIM},           0.55, 0.04, 0.05, 0.003, 0.9, 0.0, 0.5, 0.0, 1.0, 0.0, 40 + extra, 3, 1.9, false, 0},\n    };\n\n    auto stTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - stTime).count();\n    };\n\n    const double TL = 4.82;\n\n    long long bestSum = initial.sumW;\n    vector<Op> bestOps;\n\n    // Deterministic portfolio first\n    for (int i = 0; i < (int)strategies.size() && elapsed() < TL * 0.48; i++) {\n        State st = run_strategy(initial, strategies[i], rng, elapsed, TL, false);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n    }\n\n    // Randomized restarts\n    int turn = 0;\n    while (elapsed() < TL) {\n        Strategy stg = strategies[turn % strategies.size()];\n        State st = run_strategy(initial, stg, rng, elapsed, TL, true);\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n        turn++;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto& op : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << op[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 static_cast<uint32_t>(next_u64()); }\n};\n\nstruct Board {\n    array<uint8_t, 100> a;\n    Board() { a.fill(0); }\n};\n\nstruct PackedKey {\n    uint64_t w[4];\n    uint8_t turn;\n    bool operator==(const PackedKey& o) const {\n        return w[0] == o.w[0] && w[1] == o.w[1] && w[2] == o.w[2] && w[3] == o.w[3] && turn == o.turn;\n    }\n};\n\nstruct PackedKeyHash {\n    size_t operator()(const PackedKey& k) const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix(k.w[0]);\n        mix(k.w[1]);\n        mix(k.w[2]);\n        mix(k.w[3]);\n        mix(k.turn);\n        return (size_t)h;\n    }\n};\n\nstatic constexpr int N = 10;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\n// region ids:\n// 0: TL, 1: TR, 2: BL, 3: BR, 4: BC\nstruct Solver {\n    array<int, 101> f{};\n    Board board;\n\n    int target_region[4]{};   // flavor 1..3 -> region id\n    int dist_table[5][100]{};\n    int rem_after[101][4]{};\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    unordered_map<PackedKey, long long, PackedKeyHash> exact_memo;\n\n    Solver() {\n        start_time = chrono::steady_clock::now();\n        exact_memo.reserve(1 << 15);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void init_dist_table() {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int idx = r * N + c;\n                dist_table[0][idx] = r + c;                         // TL\n                dist_table[1][idx] = r + (N - 1 - c);              // TR\n                dist_table[2][idx] = (N - 1 - r) + c;              // BL\n                dist_table[3][idx] = (N - 1 - r) + (N - 1 - c);    // BR\n                dist_table[4][idx] = (N - 1 - r) + min(abs(c - 4), abs(c - 5)); // BC\n            }\n        }\n    }\n\n    void read_flavors() {\n        uint64_t seed = 1469598103934665603ull;\n        for (int i = 1; i <= 100; i++) {\n            cin >> f[i];\n            seed ^= (uint64_t)(f[i] + 1009 * i);\n            seed *= 1099511628211ull;\n        }\n        rng = XorShift64(seed ^ 0x9e3779b97f4a7c15ull);\n        init_dist_table();\n\n        for (int c = 1; c <= 3; c++) rem_after[100][c] = 0;\n        for (int t = 99; t >= 0; t--) {\n            for (int c = 1; c <= 3; c++) rem_after[t][c] = rem_after[t + 1][c];\n            rem_after[t][f[t + 1]]++;\n        }\n    }\n\n    static inline void place(Board& b, int p, int flavor) {\n        int cnt = 0;\n        for (int i = 0; i < 100; i++) {\n            if (b.a[i] == 0) {\n                ++cnt;\n                if (cnt == p) {\n                    b.a[i] = (uint8_t)flavor;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline Board tilt(const Board& in, int dir) {\n        Board out;\n        if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                int wr = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr++ * N + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < N; c++) {\n                int wr = N - 1;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr-- * N + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = 0;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc++] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = N - 1;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc--] = v;\n                }\n            }\n        }\n        return out;\n    }\n\n    static inline int component_square_sum(const Board& b) {\n        bool vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; s++) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            int qh = 0, qt = 0;\n            q[qt++] = s;\n            vis[s] = true;\n            int sz = 0;\n\n            while (qh < qt) {\n                int v = q[qh++];\n                ++sz;\n                int r = v / N, c = v % N;\n\n                if (r > 0) {\n                    int nv = v - N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (r + 1 < N) {\n                    int nv = v + N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c + 1 < N) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    inline long long heuristic(const Board& b, int turn) const {\n        int rowcnt[10][4] = {};\n        int colcnt[10][4] = {};\n        int same_adj = 0, diff_adj = 0;\n        int dist_pen = 0;\n\n        for (int idx = 0; idx < 100; idx++) {\n            uint8_t col = b.a[idx];\n            if (!col) continue;\n            int r = idx / N, c = idx % N;\n            rowcnt[r][col]++;\n            colcnt[c][col]++;\n\n            int mult = 1 + rem_after[turn][col] / 18;\n            dist_pen += dist_table[target_region[col]][idx] * mult;\n\n            if (c + 1 < N) {\n                uint8_t v = b.a[idx + 1];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t v = b.a[idx + N];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n        }\n\n        int purity = 0;\n        for (int i = 0; i < N; i++) {\n            for (int col = 1; col <= 3; col++) {\n                purity += rowcnt[i][col] * rowcnt[i][col];\n                purity += colcnt[i][col] * colcnt[i][col];\n            }\n        }\n\n        int block_score = 0;\n        for (int r = 0; r + 1 < N; r++) {\n            for (int c = 0; c + 1 < N; c++) {\n                int cnt[4] = {};\n                uint8_t v1 = b.a[r * N + c];\n                uint8_t v2 = b.a[r * N + c + 1];\n                uint8_t v3 = b.a[(r + 1) * N + c];\n                uint8_t v4 = b.a[(r + 1) * N + c + 1];\n                if (v1) cnt[v1]++;\n                if (v2) cnt[v2]++;\n                if (v3) cnt[v3]++;\n                if (v4) cnt[v4]++;\n\n                int kinds = 0, occ = 0, sq = 0;\n                for (int col = 1; col <= 3; col++) {\n                    if (cnt[col]) {\n                        kinds++;\n                        occ += cnt[col];\n                        sq += cnt[col] * cnt[col];\n                    }\n                }\n                block_score += sq;\n                if (kinds >= 2) block_score -= 2 * occ * (kinds - 1);\n            }\n        }\n\n        int comp2 = component_square_sum(b);\n\n        int wComp = 28 + turn / 4;\n        int wSame = 16;\n        int wDiff = 13;\n        int wPurity = 2;\n        int wBlock = 5;\n        int wTarget = max(2, 19 - turn / 6);\n\n        long long val = 0;\n        val += 1LL * wComp * comp2;\n        val += 1LL * wSame * same_adj;\n        val -= 1LL * wDiff * diff_adj;\n        val += 1LL * wPurity * purity;\n        val += 1LL * wBlock * block_score;\n        val -= 1LL * wTarget * dist_pen;\n        return val;\n    }\n\n    inline int greedy_action(const Board& b, int turn) const {\n        int best_dir = 0;\n        long long best_score = LLONG_MIN;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(b, dir);\n            long long sc = heuristic(nb, turn);\n            if (sc > best_score) {\n                best_score = sc;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void choose_best_mapping() {\n        vector<array<int, 3>> templates = {\n            {0, 1, 4}, // TL, TR, BC\n            {0, 1, 3}  // TL, TR, BR\n        };\n\n        const int TRIALS = 6;\n        int sampled_p[TRIALS][101]{};\n        for (int tr = 0; tr < TRIALS; tr++) {\n            for (int turn = 1; turn <= 100; turn++) {\n                int empties = 101 - turn;\n                sampled_p[tr][turn] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        array<int, 3> perm = {0, 1, 2};\n        long long best_total = -1;\n        int best_map[4] = {0, 0, 1, 4};\n\n        for (auto tpl : templates) {\n            sort(perm.begin(), perm.end());\n            do {\n                target_region[1] = tpl[perm[0]];\n                target_region[2] = tpl[perm[1]];\n                target_region[3] = tpl[perm[2]];\n\n                long long total = 0;\n                for (int tr = 0; tr < TRIALS; tr++) {\n                    Board b;\n                    for (int turn = 1; turn <= 100; turn++) {\n                        place(b, sampled_p[tr][turn], f[turn]);\n                        int dir = greedy_action(b, turn);\n                        b = tilt(b, dir);\n                    }\n                    total += component_square_sum(b);\n                }\n\n                if (total > best_total) {\n                    best_total = total;\n                    for (int c = 1; c <= 3; c++) best_map[c] = target_region[c];\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n\n        for (int c = 1; c <= 3; c++) target_region[c] = best_map[c];\n    }\n\n    PackedKey pack_key(const Board& b, int turn) const {\n        PackedKey k{};\n        k.w[0] = k.w[1] = k.w[2] = k.w[3] = 0;\n        for (int i = 0; i < 100; i++) {\n            uint64_t v = b.a[i];\n            int bit = 2 * i;\n            int blk = bit >> 6;\n            int off = bit & 63;\n            k.w[blk] |= (v << off);\n        }\n        k.turn = (uint8_t)turn;\n        return k;\n    }\n\n    long long exact_value(const Board& b, int turn) {\n        if (turn == 100) return component_square_sum(b);\n\n        PackedKey key = pack_key(b, turn);\n        auto it = exact_memo.find(key);\n        if (it != exact_memo.end()) return it->second;\n\n        int empties = 100 - turn;\n        long long sum = 0;\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = exact_value(nb, turn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n\n        exact_memo.emplace(key, sum);\n        return sum;\n    }\n\n    long long limited_value(const Board& b, int turn, int depth) {\n        if (turn == 100) return component_square_sum(b);\n        if (depth == 0) return heuristic(b, turn);\n\n        int empties = 100 - turn;\n        long long sum = 0;\n\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = limited_value(nb, turn + 1, depth - 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n        return sum;\n    }\n\n    int choose_depth(int rem_future) const {\n        double t = elapsed();\n        if (t > 1.82) return 1;\n        if (rem_future <= 4 && t < 1.72) return 100; // exact endgame\n        if (rem_future <= 7 && t < 1.70) return 3;\n        if (rem_future <= 20 && t < 1.78) return 2;\n        return 1;\n    }\n\n    int decide_action(int turn) {\n        int rem_future = 100 - turn;\n\n        if (rem_future == 0) {\n            int best_dir = 0;\n            int best_score = -1;\n            long long best_h = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(board, dir);\n                int sc = component_square_sum(nb);\n                long long h = heuristic(nb, turn);\n                if (sc > best_score || (sc == best_score && h > best_h)) {\n                    best_score = sc;\n                    best_h = h;\n                    best_dir = dir;\n                }\n            }\n            return best_dir;\n        }\n\n        int depth = choose_depth(rem_future);\n\n        array<pair<long long, int>, 4> order;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(board, dir);\n            order[dir] = {heuristic(nb, turn), dir};\n        }\n        sort(order.begin(), order.end(), greater<>());\n\n        long long best = LLONG_MIN;\n        long long best_h = LLONG_MIN;\n        int best_dir = 0;\n\n        if (depth == 100) exact_memo.clear();\n\n        for (auto [_, dir] : order) {\n            Board nb = tilt(board, dir);\n            long long v = (depth == 100 ? exact_value(nb, turn) : limited_value(nb, turn, depth));\n            long long h = heuristic(nb, turn);\n            if (v > best || (v == best && h > best_h)) {\n                best = v;\n                best_h = h;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void solve() {\n        read_flavors();\n        choose_best_mapping();\n\n        for (int turn = 1; turn <= 100; turn++) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place(board, p, f[turn]);\n            int dir = decide_action(turn);\n            board = tilt(board, dir);\n\n            cout << DIR_CH[dir] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ============================================================\n// Exact solver for eps = 0\n// ============================================================\n\nstruct ExactNoNoiseSolver {\n    int M, N, C;\n    vector<vector<int>> perm_maps;\n    vector<uint32_t> reps;\n    unordered_map<uint32_t, int> id_of;\n\n    static int unlabeled_count(int n) {\n        if (n == 4) return 11;\n        if (n == 5) return 34;\n        if (n == 6) return 156;\n        return 0;\n    }\n\n    static vector<pair<int,int>> edge_list(int n) {\n        vector<pair<int,int>> e;\n        for (int i = 0; i < n; ++i)\n            for (int j = i + 1; j < n; ++j)\n                e.push_back({i, j});\n        return e;\n    }\n\n    uint32_t permute_mask(uint32_t mask, const vector<int>& mp) const {\n        uint32_t res = 0;\n        while (mask) {\n            int b = __builtin_ctz(mask);\n            mask &= mask - 1;\n            res |= (1u << mp[b]);\n        }\n        return res;\n    }\n\n    uint32_t canonical(uint32_t mask) const {\n        uint32_t best = UINT32_MAX;\n        for (const auto& mp : perm_maps) {\n            uint32_t x = permute_mask(mask, mp);\n            if (x < best) best = x;\n        }\n        return best;\n    }\n\n    string mask_to_string(uint32_t mask) const {\n        string s;\n        s.reserve(C);\n        for (int i = 0; i < C; ++i) s.push_back(((mask >> i) & 1u) ? '1' : '0');\n        return s;\n    }\n\n    uint32_t string_to_mask(const string& s) const {\n        uint32_t mask = 0;\n        for (int i = 0; i < (int)s.size(); ++i) if (s[i] == '1') mask |= (1u << i);\n        return mask;\n    }\n\n    ExactNoNoiseSolver(int M_) : M(M_) {\n        if (M <= unlabeled_count(4)) N = 4;\n        else if (M <= unlabeled_count(5)) N = 5;\n        else N = 6;\n        C = N * (N - 1) / 2;\n\n        auto edges = edge_list(N);\n        vector<vector<int>> pos(N, vector<int>(N, -1));\n        for (int i = 0; i < C; ++i) {\n            auto [u, v] = edges[i];\n            pos[u][v] = pos[v][u] = i;\n        }\n\n        vector<int> p(N);\n        iota(p.begin(), p.end(), 0);\n        do {\n            vector<int> mp(C);\n            for (int i = 0; i < C; ++i) {\n                auto [u, v] = edges[i];\n                int a = p[u], b = p[v];\n                if (a > b) swap(a, b);\n                mp[i] = pos[a][b];\n            }\n            perm_maps.push_back(move(mp));\n        } while (next_permutation(p.begin(), p.end()));\n\n        set<uint32_t> seen;\n        uint32_t total = 1u << C;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            uint32_t can = canonical(mask);\n            if (seen.insert(can).second) reps.push_back(can);\n        }\n        sort(reps.begin(), reps.end());\n        reps.resize(M);\n        for (int i = 0; i < M; ++i) id_of[reps[i]] = i;\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (uint32_t m : reps) cout << mask_to_string(m) << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        uint32_t mask = string_to_mask(H);\n        uint32_t can = canonical(mask);\n        auto it = id_of.find(can);\n        if (it == id_of.end()) return 0;\n        return it->second;\n    }\n};\n\n// ============================================================\n// RNG\n// ============================================================\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    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// ============================================================\n// General solver\n// Equal-block threshold graphs + degree decoder + weak tie-break\n// ============================================================\n\nstruct GeneralSolver {\n    struct Candidate {\n        uint16_t mask;\n        vector<int> seq; // sorted block degree sequence, length R\n    };\n\n    struct ComboResult {\n        double proxy = -1.0;\n        int R = -1, B = -1, N = -1;\n        vector<Candidate> selected;\n    };\n\n    struct GraphCode {\n        uint16_t mask;\n        vector<int> ideal_deg;      // full sorted degree sequence, length N\n        vector<uint8_t> edgeBits;   // upper triangle\n        string gstr;\n    };\n\n    int M;\n    double eps, a, c;\n\n    int R, B, N, C;\n    vector<GraphCode> codes;\n    vector<int> eu, ev;\n\n    // Final decoder pack\n    int S;\n    int TOPL;\n    double mu_ideal;\n    double lambda_nd;\n    vector<vector<uint16_t>> feat_samples; // [M*S][2N]\n    vector<vector<float>> expected_deg;    // [M][N]\n\n    static int seq_dist2(const vector<int>& x, const vector<int>& y) {\n        int s = 0;\n        for (int i = 0; i < (int)x.size(); ++i) {\n            int d = x[i] - y[i];\n            s += d * d;\n        }\n        return s;\n    }\n\n    static vector<int> block_degree_seq(uint16_t mask, int R, int B) {\n        vector<int> deg(R);\n        int suf = 0;\n        for (int i = R - 1; i >= 0; --i) {\n            int z = (mask >> i) & 1u;\n            deg[i] = B * suf + (z ? (B - 1 + B * i) : 0);\n            suf += z;\n        }\n        sort(deg.begin(), deg.end());\n        return deg;\n    }\n\n    static string build_graph_string(uint16_t mask, int R, int B, vector<uint8_t>* edgeBits = nullptr) {\n        int N = R * B;\n        string g;\n        g.reserve(N * (N - 1) / 2);\n        if (edgeBits) edgeBits->clear(), edgeBits->reserve(N * (N - 1) / 2);\n\n        for (int u = 0; u < N; ++u) {\n            int bu = u / B;\n            for (int v = u + 1; v < N; ++v) {\n                int bv = v / B;\n                bool e;\n                if (bu == bv) e = ((mask >> bu) & 1u);\n                else e = ((mask >> max(bu, bv)) & 1u); // later block decides\n                g.push_back(e ? '1' : '0');\n                if (edgeBits) edgeBits->push_back((uint8_t)e);\n            }\n        }\n        return g;\n    }\n\n    double eval_proxy(const vector<Candidate>& sel, int B, int N) const {\n        double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n        double avg_p = 0.0;\n        const double SQRT2 = sqrt(2.0);\n\n        for (int i = 0; i < M; ++i) {\n            int best_d2 = INT_MAX;\n            for (int j = 0; j < M; ++j) if (i != j) {\n                best_d2 = min(best_d2, seq_dist2(sel[i].seq, sel[j].seq));\n            }\n            double p = 0.0;\n            if (sigma > 1e-15) {\n                double D = a * sqrt((double)B * best_d2);\n                double x = D / (2.0 * sigma);\n                p = 0.5 * erfc(x / SQRT2);\n            }\n            avg_p += p;\n        }\n        avg_p /= M;\n\n        double per_query = max(0.0, 1.0 - 0.1 * avg_p);\n        return pow(per_query, 100.0) / N;\n    }\n\n    vector<Candidate> greedy_select(const vector<Candidate>& cands, int start_idx) const {\n        int CC = (int)cands.size();\n        vector<int> minD(CC, INT_MAX);\n        vector<char> used(CC, 0);\n        vector<int> sel_idx;\n        sel_idx.reserve(M);\n\n        auto add_one = [&](int idx) {\n            used[idx] = 1;\n            sel_idx.push_back(idx);\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[idx].seq, cands[i].seq);\n                if (d2 < minD[i]) minD[i] = d2;\n            }\n        };\n\n        add_one(start_idx);\n        if (M >= 2) {\n            int far = -1, far_d = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[start_idx].seq, cands[i].seq);\n                if (d2 > far_d) far_d = d2, far = i;\n            }\n            add_one(far);\n        }\n\n        while ((int)sel_idx.size() < M) {\n            int best = -1, best_d = -1, best_sum = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int candd = minD[i];\n                int sumd = 0;\n                for (int x : sel_idx) sumd += seq_dist2(cands[i].seq, cands[x].seq);\n                if (candd > best_d || (candd == best_d && sumd > best_sum)) {\n                    best_d = candd;\n                    best_sum = sumd;\n                    best = i;\n                }\n            }\n            add_one(best);\n        }\n\n        vector<Candidate> sel;\n        sel.reserve(M);\n        for (int idx : sel_idx) sel.push_back(cands[idx]);\n        sort(sel.begin(), sel.end(), [](const Candidate& lhs, const Candidate& rhs) {\n            return lhs.seq < rhs.seq;\n        });\n        return sel;\n    }\n\n    ComboResult try_combo(int R, int B) const {\n        ComboResult res;\n        res.R = R;\n        res.B = B;\n        res.N = R * B;\n\n        map<vector<int>, uint16_t> uniq;\n        uint16_t total = (uint16_t)(1u << R);\n        for (uint16_t mask = 0; mask < total; ++mask) {\n            vector<int> seq = block_degree_seq(mask, R, B);\n            if (!uniq.count(seq)) uniq.emplace(seq, mask);\n        }\n\n        vector<Candidate> cands;\n        cands.reserve(uniq.size());\n        for (auto& kv : uniq) cands.push_back({kv.second, kv.first});\n        if ((int)cands.size() < M) return res;\n\n        int CC = (int)cands.size();\n        vector<int> sums(CC);\n        for (int i = 0; i < CC; ++i) {\n            sums[i] = accumulate(cands[i].seq.begin(), cands[i].seq.end(), 0);\n        }\n\n        int min_idx = 0, max_idx = 0;\n        for (int i = 1; i < CC; ++i) {\n            if (sums[i] < sums[min_idx]) min_idx = i;\n            if (sums[i] > sums[max_idx]) max_idx = i;\n        }\n\n        vector<pair<int,int>> ord;\n        ord.reserve(CC);\n        for (int i = 0; i < CC; ++i) ord.push_back({sums[i], i});\n        sort(ord.begin(), ord.end());\n        int med_idx = ord[CC / 2].second;\n\n        vector<int> starts = {min_idx, max_idx, med_idx};\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int st : starts) {\n            vector<Candidate> sel = greedy_select(cands, st);\n            double pr = eval_proxy(sel, B, R * B);\n            if (pr > res.proxy) {\n                res.proxy = pr;\n                res.selected = move(sel);\n            }\n        }\n        return res;\n    }\n\n    void prepare_pairs(int N_) {\n        N = N_;\n        C = N * (N - 1) / 2;\n        eu.clear();\n        ev.clear();\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n    }\n\n    static vector<uint16_t> sample_noisy_feature(\n        int N,\n        const vector<int>& eu,\n        const vector<int>& ev,\n        const vector<uint8_t>& edgeBits,\n        uint32_t thr,\n        SplitMix64& rng\n    ) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int C = (int)edgeBits.size();\n        for (int idx = 0; idx < C; ++idx) {\n            bool b = edgeBits[idx];\n            if (rng.next_u32() < thr) b = !b;\n            if (b) {\n                int u = eu[idx], v = ev[idx];\n                adj[u][v] = adj[v][u] = 1;\n                ++deg[u];\n                ++deg[v];\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static vector<uint16_t> feature_from_string(const string& H, int N) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int p = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                if (H[p++] == '1') {\n                    adj[i][j] = adj[j][i] = 1;\n                    ++deg[i];\n                    ++deg[j];\n                }\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static double degree_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int M,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg,\n        double mu_ideal\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i] - (int)s[2 * i]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        double ideal = 0.0;\n        for (int i = 0; i < N; ++i) ideal += fabs((double)qfeat[2 * i] - expected_deg[g][i]);\n\n        return avgBest + mu_ideal * ideal;\n    }\n\n    static double ndsum_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i + 1] - (int)s[2 * i + 1]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        return avgBest / max(1, N);\n    }\n\n    static int decode_feature(\n        const vector<uint16_t>& qfeat,\n        int M,\n        int S,\n        int N,\n        int TOPL,\n        double mu_ideal,\n        double lambda_nd,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg\n    ) {\n        vector<pair<double,int>> deg_rank;\n        deg_rank.reserve(M);\n        for (int g = 0; g < M; ++g) {\n            double dc = degree_cost_knn(qfeat, g, M, S, N, feat_samples, expected_deg, mu_ideal);\n            deg_rank.push_back({dc, g});\n        }\n\n        if (TOPL < M) {\n            nth_element(deg_rank.begin(), deg_rank.begin() + TOPL, deg_rank.end());\n            deg_rank.resize(TOPL);\n        }\n\n        int best_id = 0;\n        double best_cost = 1e300;\n\n        for (auto [dc, g] : deg_rank) {\n            double nc = ndsum_cost_knn(qfeat, g, S, N, feat_samples);\n            double total = dc + lambda_nd * nc;\n            if (total < best_cost) {\n                best_cost = total;\n                best_id = g;\n            }\n        }\n        return best_id;\n    }\n\n    vector<GraphCode> build_graph_codes_from_combo(const ComboResult& combo) const {\n        vector<GraphCode> ret;\n        ret.reserve(M);\n        int N = combo.R * combo.B;\n\n        for (const auto& cand : combo.selected) {\n            vector<uint8_t> bits;\n            string g = build_graph_string(cand.mask, combo.R, combo.B, &bits);\n\n            vector<int> ideal_deg;\n            ideal_deg.reserve(N);\n            for (int d : cand.seq) {\n                for (int t = 0; t < combo.B; ++t) ideal_deg.push_back(d);\n            }\n\n            ret.push_back({cand.mask, move(ideal_deg), move(bits), move(g)});\n        }\n        return ret;\n    }\n\n    static double validate_combo(\n        int M,\n        double eps,\n        const ComboResult& combo,\n        const vector<GraphCode>& codes\n    ) {\n        int N = combo.N;\n        int C = N * (N - 1) / 2;\n        vector<int> eu, ev;\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n\n        int S_train, T_val, TOPL;\n        double mu_ideal = 0.25;\n        double lambda_nd;\n        if (eps < 0.08) {\n            S_train = 4;\n            T_val = 2;\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            S_train = 6;\n            T_val = 2;\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            S_train = 8;\n            T_val = 2;\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n\n        vector<vector<uint16_t>> feat_samples(M * S_train);\n        vector<vector<float>> expected_deg(M, vector<float>(N));\n        double a = 1.0 - 2.0 * eps;\n        double c = eps * (N - 1);\n\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x1234567890abcdefULL + (uint64_t)N * 1009 + M * 17 + (uint64_t)(eps * 1000 + 0.5));\n\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S_train; ++t) {\n                feat_samples[g * S_train + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n\n        int correct = 0, total = 0;\n        for (int tg = 0; tg < M; ++tg) {\n            for (int tv = 0; tv < T_val; ++tv) {\n                auto q = sample_noisy_feature(N, eu, ev, codes[tg].edgeBits, thr, rng);\n                int pred = decode_feature(q, M, S_train, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n                if (pred == tg) ++correct;\n                ++total;\n            }\n        }\n\n        double acc = (double)correct / total;\n        return 100.0 * (1.0 - acc) * log(0.9) - log((double)N);\n    }\n\n    GeneralSolver(int M_, double eps_) : M(M_), eps(eps_) {\n        a = 1.0 - 2.0 * eps;\n        c = 0.0;\n\n        vector<ComboResult> pool;\n\n        int minR = 0;\n        while ((1u << minR) < (unsigned)M) ++minR;\n        minR = max(minR, 4);\n        int maxR = min(10, minR + 5);\n\n        for (int r = minR; r <= maxR; ++r) {\n            int maxB = 100 / r;\n            for (int b = 1; b <= maxB; ++b) {\n                ComboResult cur = try_combo(r, b);\n                if (cur.proxy > 0) pool.push_back(move(cur));\n            }\n        }\n\n        if (pool.empty()) {\n            // conservative fallback\n            R = minR;\n            B = 100 / R;\n            N = R * B;\n            prepare_pairs(N);\n\n            vector<Candidate> fallback;\n            for (int k = 0; k < M; ++k) {\n                uint16_t mask = (uint16_t)k;\n                fallback.push_back({mask, block_degree_seq(mask, R, B)});\n            }\n            sort(fallback.begin(), fallback.end(), [](const Candidate& x, const Candidate& y) {\n                return x.seq < y.seq;\n            });\n\n            ComboResult combo;\n            combo.R = R; combo.B = B; combo.N = N; combo.selected = fallback;\n            codes = build_graph_codes_from_combo(combo);\n        } else {\n            sort(pool.begin(), pool.end(), [](const ComboResult& x, const ComboResult& y) {\n                return x.proxy > y.proxy;\n            });\n\n            int checkTop = min<int>(8, pool.size());\n            int best_i = 0;\n            double best_val = -1e300;\n\n            for (int i = 0; i < checkTop; ++i) {\n                auto tmp_codes = build_graph_codes_from_combo(pool[i]);\n                double val = validate_combo(M, eps, pool[i], tmp_codes);\n                if (val > best_val) {\n                    best_val = val;\n                    best_i = i;\n                }\n            }\n\n            R = pool[best_i].R;\n            B = pool[best_i].B;\n            N = pool[best_i].N;\n            codes = build_graph_codes_from_combo(pool[best_i]);\n        }\n\n        prepare_pairs(N);\n        c = eps * (N - 1);\n\n        if (eps < 0.05) S = 8;\n        else if (eps < 0.15) S = 12;\n        else if (eps < 0.25) S = 16;\n        else S = 20;\n        if (M < 20) S += 4;\n        S = min(S, 24);\n\n        if (eps < 0.08) {\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n        mu_ideal = 0.25;\n\n        feat_samples.assign(M * S, {});\n        expected_deg.assign(M, vector<float>(N));\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) {\n                expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n            }\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x3141592653589793ULL + (uint64_t)N * 10007 + M * 911 + (uint64_t)(eps * 1000 + 0.5));\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S; ++t) {\n                feat_samples[g * S + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (const auto& code : codes) cout << code.gstr << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        auto qfeat = feature_from_string(H, N);\n        return decode_feature(qfeat, M, S, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n    }\n};\n\n// ============================================================\n// main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    if (fabs(eps) < 1e-12) {\n        ExactNoNoiseSolver solver(M);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        GeneralSolver solver(M, eps);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\nstatic const int MAXD = 30;\n\nstruct Solver {\n    struct Edge {\n        int u, v;\n        ll w;\n        int cell = 0;\n        double usage = 0.0;\n        ll detour = 0;\n        double imp = 1.0;\n    };\n    struct Adj {\n        int to, id;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<pair<int,int>> coord;\n    vector<vector<Adj>> g;\n    vector<int> degv;\n\n    // assignment\n    vector<int> dayOf;\n    vector<int> posInDay;\n    vector<vector<int>> dayEdges;\n    vector<int> dayCnt;\n    vector<double> dayLoad;\n\n    // counts\n    vector<array<int, MAXD>> cntV;\n    vector<array<int, MAXD>> cntCell;\n\n    // dangerous edge-pair conflicts\n    vector<vector<int>> conflicts;\n    int bitBlocks;\n    vector<unsigned long long> confBitsFlat;\n    vector<array<int, MAXD>> confCnt; // confCnt[e][d] = # conflicting edges of e assigned to day d\n\n    // geometry\n    int G, C;\n\n    // proxy weights\n    double WA, WB, WC, WQ;\n\n    // sampled evaluation\n    vector<int> landmarks;\n    int L_imp = 12;\n    int L_eval = 4;\n    vector<vector<ll>> origEvalDist;\n    vector<ll> dayScore;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver() {\n        rng.seed((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    inline double comb2(int x) const {\n        return 0.5 * x * (x - 1);\n    }\n\n    inline int bit_index(int e, int b) const {\n        return e * bitBlocks + b;\n    }\n\n    inline bool is_conflict(int a, int b) const {\n        return (confBitsFlat[bit_index(a, b >> 6)] >> (b & 63)) & 1ULL;\n    }\n\n    void add_conflict(int a, int b) {\n        if (a == b) return;\n        if (is_conflict(a, b)) return;\n        confBitsFlat[bit_index(a, b >> 6)] |= 1ULL << (b & 63);\n        confBitsFlat[bit_index(b, a >> 6)] |= 1ULL << (a & 63);\n        conflicts[a].push_back(b);\n        conflicts[b].push_back(a);\n    }\n\n    void read_input() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        degv.assign(N, 0);\n\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            ll w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i] = {u, v, w};\n            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            degv[u]++;\n            degv[v]++;\n        }\n\n        coord.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> coord[i].first >> coord[i].second;\n        }\n\n        G = max(4, min(6, (int)llround(sqrt((double)D)) + 1));\n        C = G * G;\n        for (int i = 0; i < M; i++) {\n            double mx = (coord[edges[i].u].first + coord[edges[i].v].first) * 0.5;\n            double my = (coord[edges[i].u].second + coord[edges[i].v].second) * 0.5;\n            int cx = min(G - 1, max(0, (int)(mx * G / 1001.0)));\n            int cy = min(G - 1, max(0, (int)(my * G / 1001.0)));\n            edges[i].cell = cy * G + cx;\n        }\n\n        dayOf.assign(M, -1);\n        posInDay.assign(M, -1);\n        dayEdges.assign(D, {});\n        dayCnt.assign(D, 0);\n        dayLoad.assign(D, 0.0);\n\n        cntV.assign(N, {});\n        for (auto &a : cntV) a.fill(0);\n\n        cntCell.assign(C, {});\n        for (auto &a : cntCell) a.fill(0);\n\n        conflicts.assign(M, {});\n        bitBlocks = (M + 63) >> 6;\n        confBitsFlat.assign(M * bitBlocks, 0ULL);\n        confCnt.assign(M, {});\n        for (auto &a : confCnt) a.fill(0);\n\n        WA = 0.025; // day load balance\n        WB = 4.5;   // same-vertex crowding\n        WC = 0.6;   // same-cell crowding\n        WQ = 0.010; // soft day-count balance\n    }\n\n    void dijkstra_full(int src,\n                       vector<ll> &dist,\n                       int skipEdge = -1,\n                       int skipDay = -1,\n                       int target = -1,\n                       vector<int> *parV = nullptr,\n                       vector<int> *parE = nullptr) {\n        dist.assign(N, INF64);\n        if (parV) parV->assign(N, -1);\n        if (parE) parE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n            if (v == target) return;\n\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == skipEdge) continue;\n                if (skipDay >= 0 && dayOf[id] == skipDay) continue;\n                int to = ad.to;\n                ll nd = cd + edges[id].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parV) (*parV)[to] = v;\n                    if (parE) (*parE)[to] = id;\n                    pq.push({nd, to});\n                } else if (parE && nd == dist[to]) {\n                    if ((*parE)[to] == -1 || id < (*parE)[to]) {\n                        (*parV)[to] = v;\n                        (*parE)[to] = id;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> choose_landmarks(int L) {\n        L = min(L, N);\n        vector<int> res;\n        res.reserve(L);\n\n        auto dist2 = [&](int a, int b) -> ll {\n            ll dx = coord[a].first - coord[b].first;\n            ll dy = coord[a].second - coord[b].second;\n            return dx * dx + dy * dy;\n        };\n\n        vector<ll> best(N, (1LL << 62));\n        int first = 0;\n        res.push_back(first);\n        for (int i = 0; i < N; i++) best[i] = dist2(i, first);\n\n        while ((int)res.size() < L) {\n            int cand = -1;\n            ll mx = -1;\n            for (int i = 0; i < N; i++) {\n                if (best[i] > mx) {\n                    mx = best[i];\n                    cand = i;\n                }\n            }\n            res.push_back(cand);\n            for (int i = 0; i < N; i++) best[i] = min(best[i], dist2(i, cand));\n        }\n        return res;\n    }\n\n    void compute_importance() {\n        landmarks = choose_landmarks(L_imp);\n        L_imp = (int)landmarks.size();\n        L_eval = min(L_eval, L_imp);\n        origEvalDist.assign(L_eval, vector<ll>(N, INF64));\n\n        vector<ll> dist;\n        vector<int> parV, parE;\n\n        for (int li = 0; li < L_imp; li++) {\n            int s = landmarks[li];\n            dijkstra_full(s, dist, -1, -1, -1, &parV, &parE);\n\n            if (li < L_eval) origEvalDist[li] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sz(N, 1);\n            for (int v : ord) {\n                if (v == s) continue;\n                int pe = parE[v];\n                int pv = parV[v];\n                if (pe >= 0) {\n                    edges[pe].usage += sz[v];\n                    sz[pv] += sz[v];\n                }\n            }\n        }\n\n        vector<ll> dist2;\n        for (int eid = 0; eid < M; eid++) {\n            int s = edges[eid].u;\n            int t = edges[eid].v;\n            dijkstra_full(s, dist2, eid, -1, t, nullptr, nullptr);\n            ll alt = dist2[t];\n            if (alt >= INF64 / 2) alt = (ll)1e18;\n            edges[eid].detour = max<ll>(0, alt - edges[eid].w);\n        }\n\n        double avgUsage = 0.0, avgDet = 0.0;\n        for (int i = 0; i < M; i++) {\n            avgUsage += edges[i].usage + 1.0;\n            avgDet += (double)edges[i].detour + 1.0;\n        }\n        avgUsage /= M;\n        avgDet /= M;\n\n        vector<double> raw(M);\n        double meanRaw = 0.0;\n        for (int i = 0; i < M; i++) {\n            double u = (edges[i].usage + 1.0) / avgUsage;\n            double d = ((double)edges[i].detour + 1.0) / avgDet;\n            raw[i] = u * d;\n            meanRaw += raw[i];\n        }\n        meanRaw /= M;\n        if (meanRaw <= 0) meanRaw = 1.0;\n\n        for (int i = 0; i < M; i++) {\n            edges[i].imp = raw[i] / meanRaw;\n        }\n    }\n\n    void compute_two_edge_cut_conflicts() {\n        vector<int> tin(N), low(N);\n        int timer = 0;\n\n        function<void(int,int,int, vector<int>&)> dfs = [&](int v, int pe, int banned, vector<int> &bridges) {\n            tin[v] = low[v] = timer++;\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == banned) continue;\n                if (id == pe) continue;\n                int to = ad.to;\n                if (tin[to] != -1) {\n                    low[v] = min(low[v], tin[to]);\n                } else {\n                    dfs(to, id, banned, bridges);\n                    low[v] = min(low[v], low[to]);\n                    if (low[to] > tin[v]) bridges.push_back(id);\n                }\n            }\n        };\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), -1);\n            fill(low.begin(), low.end(), -1);\n            timer = 0;\n            vector<int> bridges;\n            for (int s = 0; s < N; s++) {\n                if (tin[s] == -1) dfs(s, -1, banned, bridges);\n            }\n            for (int f : bridges) {\n                if (f > banned) add_conflict(banned, f);\n            }\n        }\n    }\n\n    inline bool touches(int eid, int v) const {\n        return edges[eid].u == v || edges[eid].v == v;\n    }\n\n    void clear_assignment() {\n        fill(dayOf.begin(), dayOf.end(), -1);\n        fill(posInDay.begin(), posInDay.end(), -1);\n        dayEdges.assign(D, {});\n        fill(dayCnt.begin(), dayCnt.end(), 0);\n        fill(dayLoad.begin(), dayLoad.end(), 0.0);\n        for (auto &a : cntV) a.fill(0);\n        for (auto &a : cntCell) a.fill(0);\n        for (auto &a : confCnt) a.fill(0);\n        dayScore.clear();\n    }\n\n    void add_edge_to_day(int eid, int d) {\n        dayOf[eid] = d;\n        posInDay[eid] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(eid);\n\n        dayCnt[d]++;\n        dayLoad[d] += edges[eid].imp;\n\n        cntV[edges[eid].u][d]++;\n        cntV[edges[eid].v][d]++;\n        cntCell[edges[eid].cell][d]++;\n\n        for (int f : conflicts[eid]) confCnt[f][d]++;\n    }\n\n    void remove_edge_from_day(int eid, int d) {\n        int pos = posInDay[eid];\n        int last = dayEdges[d].back();\n        dayEdges[d][pos] = last;\n        posInDay[last] = pos;\n        dayEdges[d].pop_back();\n\n        dayCnt[d]--;\n        dayLoad[d] -= edges[eid].imp;\n\n        cntV[edges[eid].u][d]--;\n        cntV[edges[eid].v][d]--;\n        cntCell[edges[eid].cell][d]--;\n\n        for (int f : conflicts[eid]) confCnt[f][d]--;\n\n        dayOf[eid] = -1;\n        posInDay[eid] = -1;\n    }\n\n    void move_edge_day(int eid, int nd) {\n        int od = dayOf[eid];\n        if (od == nd) return;\n        remove_edge_from_day(eid, od);\n        add_edge_to_day(eid, nd);\n    }\n\n    void rebuild_from_assignment(const vector<int> &assign) {\n        clear_assignment();\n        for (int e = 0; e < M; e++) add_edge_to_day(e, assign[e]);\n    }\n\n    inline bool feasible_add_strict(int eid, int d) const {\n        if (dayCnt[d] >= K) return false;\n        if (confCnt[eid][d] > 0) return false;\n        const auto &e = edges[eid];\n        if (cntV[e.u][d] + 1 >= degv[e.u]) return false;\n        if (cntV[e.v][d] + 1 >= degv[e.v]) return false;\n        return true;\n    }\n\n    inline bool feasible_add_relaxed_vertex(int eid, int d) const {\n        if (dayCnt[d] >= K) return false;\n        if (confCnt[eid][d] > 0) return false;\n        return true;\n    }\n\n    inline double greedy_add_cost(int eid, int d) const {\n        const auto &e = edges[eid];\n        double x = e.imp;\n        double cost = 0.0;\n        cost += WA * (2.0 * dayLoad[d] * x + x * x);\n        cost += WB * (cntV[e.u][d] + cntV[e.v][d]);\n        cost += WC * cntCell[e.cell][d];\n        cost += WQ * (2.0 * dayCnt[d] + 1.0);\n        return cost;\n    }\n\n    void build_initial_solution_variant(int variant) {\n        clear_assignment();\n\n        double alpha = 0.14 + 0.04 * (variant % 3);\n        double noiseAmp = 0.015 + 0.015 * (variant % 2);\n\n        vector<pair<double,int>> ord;\n        ord.reserve(M);\n        uniform_real_distribution<double> ur(-noiseAmp, noiseAmp);\n        for (int i = 0; i < M; i++) {\n            double base = edges[i].imp * (1.0 + alpha * sqrt((double)conflicts[i].size() + 1.0));\n            base *= (1.0 + ur(rng));\n            ord.push_back({base, i});\n        }\n        sort(ord.begin(), ord.end(), [&](auto &a, auto &b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        vector<int> days(D);\n        iota(days.begin(), days.end(), 0);\n\n        for (auto &[_, eid] : ord) {\n            shuffle(days.begin(), days.end(), rng);\n\n            double bestCost = 1e100;\n            int bestDay = -1;\n\n            for (int d : days) {\n                if (!feasible_add_strict(eid, d)) continue;\n                double c = greedy_add_cost(eid, d);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestDay = d;\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (!feasible_add_relaxed_vertex(eid, d)) continue;\n                    double c = greedy_add_cost(eid, d) + 1e5;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (dayCnt[d] >= K) continue;\n                    const auto &e = edges[eid];\n                    double c = greedy_add_cost(eid, d);\n                    c += 1e7 * confCnt[eid][d];\n                    if (cntV[e.u][d] + 1 >= degv[e.u]) c += 1e6;\n                    if (cntV[e.v][d] + 1 >= degv[e.v]) c += 1e6;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d = 0; d < D; d++) {\n                    if (dayCnt[d] < K) {\n                        bestDay = d;\n                        break;\n                    }\n                }\n            }\n\n            add_edge_to_day(eid, bestDay);\n        }\n    }\n\n    bool day_connected(int blockedDay, vector<int> *compOut = nullptr) {\n        vector<int> comp(N, -1);\n        queue<int> q;\n        int cc = 0;\n\n        for (int s = 0; s < N; s++) {\n            if (comp[s] != -1) continue;\n            comp[s] = cc;\n            q.push(s);\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                for (const auto &ad : g[v]) {\n                    if (dayOf[ad.id] == blockedDay) continue;\n                    int to = ad.to;\n                    if (comp[to] == -1) {\n                        comp[to] = cc;\n                        q.push(to);\n                    }\n                }\n            }\n            cc++;\n            if (!compOut && cc >= 2) return false;\n        }\n\n        if (compOut) *compOut = move(comp);\n        return cc == 1;\n    }\n\n    struct InitMetric {\n        int badConn;\n        ll badConflict;\n        int badVertex;\n        double proxy;\n    };\n\n    InitMetric evaluate_current_assignment() {\n        int badConn = 0;\n        for (int d = 0; d < D; d++) {\n            if (!day_connected(d)) badConn++;\n        }\n\n        ll badConflict = 0;\n        for (int e = 0; e < M; e++) {\n            badConflict += confCnt[e][dayOf[e]];\n        }\n        badConflict /= 2;\n\n        int badVertex = 0;\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) {\n                if (cntV[v][d] >= degv[v]) badVertex++;\n            }\n        }\n\n        double proxy = 0.0;\n        for (int d = 0; d < D; d++) {\n            proxy += WA * dayLoad[d] * dayLoad[d];\n            proxy += WQ * dayCnt[d] * dayCnt[d];\n        }\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) proxy += WB * comb2(cntV[v][d]);\n        }\n        for (int c = 0; c < C; c++) {\n            for (int d = 0; d < D; d++) proxy += WC * comb2(cntCell[c][d]);\n        }\n\n        return {badConn, badConflict, badVertex, proxy};\n    }\n\n    bool better_metric(const InitMetric &a, const InitMetric &b) {\n        if (a.badConn != b.badConn) return a.badConn < b.badConn;\n        if (a.badConflict != b.badConflict) return a.badConflict < b.badConflict;\n        if (a.badVertex != b.badVertex) return a.badVertex < b.badVertex;\n        return a.proxy < b.proxy;\n    }\n\n    void multi_start_initial_solution() {\n        vector<int> bestAssign;\n        InitMetric bestMet{INT_MAX, (ll)4e18, INT_MAX, 1e100};\n\n        int tries = 0;\n        while (tries < 4 && elapsed() < 1.15) {\n            build_initial_solution_variant(tries);\n            InitMetric met = evaluate_current_assignment();\n            if (bestAssign.empty() || better_metric(met, bestMet)) {\n                bestAssign = dayOf;\n                bestMet = met;\n            }\n            tries++;\n        }\n\n        if (bestAssign.empty()) build_initial_solution_variant(0);\n        else rebuild_from_assignment(bestAssign);\n    }\n\n    inline bool valid_swap_hard(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return false;\n\n        int ic = is_conflict(e1, e2) ? 1 : 0;\n        if (confCnt[e1][b] - ic > 0) return false;\n        if (confCnt[e2][a] - ic > 0) return false;\n\n        int vs[4] = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs, vs + 4);\n        int m = unique(vs, vs + 4) - vs;\n\n        for (int i = 0; i < m; i++) {\n            int v = vs[i];\n            int cntA = cntV[v][a];\n            int cntB = cntV[v][b];\n            int newA = cntA - (touches(e1, v) ? 1 : 0) + (touches(e2, v) ? 1 : 0);\n            int newB = cntB - (touches(e2, v) ? 1 : 0) + (touches(e1, v) ? 1 : 0);\n            if (newA >= degv[v]) return false;\n            if (newB >= degv[v]) return false;\n        }\n        return true;\n    }\n\n    inline bool valid_move_hard(int e, int toDay) const {\n        int fromDay = dayOf[e];\n        if (fromDay == toDay) return false;\n        if (dayCnt[toDay] >= K) return false;\n        if (confCnt[e][toDay] > 0) return false;\n\n        const auto &E = edges[e];\n        if (cntV[E.u][toDay] + 1 >= degv[E.u]) return false;\n        if (cntV[E.v][toDay] + 1 >= degv[E.v]) return false;\n        return true;\n    }\n\n    double proxy_swap_delta(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return 0.0;\n\n        const auto &E1 = edges[e1];\n        const auto &E2 = edges[e2];\n        double delta = 0.0;\n\n        {\n            double la = dayLoad[a], lb = dayLoad[b];\n            double x = E1.imp, y = E2.imp;\n            double nla = la - x + y;\n            double nlb = lb - y + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n\n        {\n            int vs[4] = {E1.u, E1.v, E2.u, E2.v};\n            sort(vs, vs + 4);\n            int m = unique(vs, vs + 4) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][a];\n                int cb = cntV[v][b];\n                int da = 0;\n                if (touches(e1, v)) da--;\n                if (touches(e2, v)) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WB * add;\n        }\n\n        {\n            int cs[2] = {E1.cell, E2.cell};\n            sort(cs, cs + 2);\n            int m = unique(cs, cs + 2) - cs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int c = cs[i];\n                int ca = cntCell[c][a];\n                int cb = cntCell[c][b];\n                int da = 0;\n                if (E1.cell == c) da--;\n                if (E2.cell == c) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WC * add;\n        }\n\n        return delta;\n    }\n\n    double proxy_move_delta(int e, int toDay) const {\n        int fromDay = dayOf[e];\n        if (fromDay == toDay) return 0.0;\n\n        const auto &E = edges[e];\n        double x = E.imp;\n        double delta = 0.0;\n\n        {\n            double la = dayLoad[fromDay], lb = dayLoad[toDay];\n            double nla = la - x;\n            double nlb = lb + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n        {\n            double ca = dayCnt[fromDay], cb = dayCnt[toDay];\n            double nca = ca - 1, ncb = cb + 1;\n            delta += WQ * (nca * nca + ncb * ncb - ca * ca - cb * cb);\n        }\n        {\n            int vs[2] = {E.u, E.v};\n            sort(vs, vs + 2);\n            int m = unique(vs, vs + 2) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][fromDay];\n                int cb = cntV[v][toDay];\n                add += comb2(ca - 1) + comb2(cb + 1) - comb2(ca) - comb2(cb);\n            }\n            delta += WB * add;\n        }\n        {\n            int c = E.cell;\n            int ca = cntCell[c][fromDay];\n            int cb = cntCell[c][toDay];\n            delta += WC * (comb2(ca - 1) + comb2(cb + 1) - comb2(ca) - comb2(cb));\n        }\n\n        return delta;\n    }\n\n    void apply_swap(int e1, int e2) {\n        int d1 = dayOf[e1], d2 = dayOf[e2];\n        if (d1 == d2) return;\n        remove_edge_from_day(e1, d1);\n        remove_edge_from_day(e2, d2);\n        add_edge_to_day(e1, d2);\n        add_edge_to_day(e2, d1);\n    }\n\n    void apply_move(int e, int toDay) {\n        move_edge_day(e, toDay);\n    }\n\n    int pick_edge_from_day(int d, bool highImp) {\n        const auto &vec = dayEdges[d];\n        int sz = (int)vec.size();\n        if (sz == 0) return -1;\n        int best = vec[rng() % sz];\n        for (int t = 0; t < 3; t++) {\n            int cand = vec[rng() % sz];\n            if (highImp) {\n                if (edges[cand].imp > edges[best].imp) best = cand;\n            } else {\n                if (edges[cand].imp < edges[best].imp) best = cand;\n            }\n        }\n        return best;\n    }\n\n    void repair_connectivity(double timeLimit) {\n        vector<int> comp;\n        while (elapsed() < timeLimit) {\n            int badDay = -1;\n            for (int d = 0; d < D; d++) {\n                if (!day_connected(d)) {\n                    badDay = d;\n                    break;\n                }\n            }\n            if (badDay == -1) break;\n\n            day_connected(badDay, &comp);\n\n            vector<int> candE;\n            candE.reserve(dayEdges[badDay].size());\n            for (int e : dayEdges[badDay]) {\n                if (comp[edges[e].u] != comp[edges[e].v]) candE.push_back(e);\n            }\n            if (candE.empty()) candE = dayEdges[badDay];\n\n            sort(candE.begin(), candE.end(), [&](int a, int b) {\n                return edges[a].imp > edges[b].imp;\n            });\n\n            bool improved = false;\n\n            // 1) relocate first\n            {\n                double bestDelta = 1e100;\n                int bestE = -1, bestTo = -1;\n\n                int limE = min((int)candE.size(), 30);\n                vector<int> dayOrd(D);\n                iota(dayOrd.begin(), dayOrd.end(), 0);\n                sort(dayOrd.begin(), dayOrd.end(), [&](int x, int y) {\n                    if (dayCnt[x] != dayCnt[y]) return dayCnt[x] < dayCnt[y];\n                    return dayLoad[x] < dayLoad[y];\n                });\n\n                for (int ii = 0; ii < limE && elapsed() < timeLimit; ii++) {\n                    int e = candE[ii];\n                    for (int t = 0; t < D && elapsed() < timeLimit; t++) {\n                        int d2 = dayOrd[t];\n                        if (d2 == badDay) continue;\n                        if (!valid_move_hard(e, d2)) continue;\n\n                        double delta = proxy_move_delta(e, d2);\n                        int old = dayOf[e];\n                        apply_move(e, d2);\n                        bool ok2 = day_connected(d2);\n                        bool ok1 = day_connected(badDay);\n                        apply_move(e, old);\n\n                        if (ok1 && ok2 && delta < bestDelta) {\n                            bestDelta = delta;\n                            bestE = e;\n                            bestTo = d2;\n                        }\n                    }\n                }\n\n                if (bestE != -1) {\n                    apply_move(bestE, bestTo);\n                    improved = true;\n                }\n            }\n            if (improved) continue;\n\n            // 2) swap fallback\n            {\n                double bestDelta = 1e100;\n                int bestE = -1, bestF = -1;\n\n                int limE = min((int)candE.size(), 25);\n                for (int ii = 0; ii < limE && elapsed() < timeLimit; ii++) {\n                    int e = candE[ii];\n                    for (int d2 = 0; d2 < D && elapsed() < timeLimit; d2++) {\n                        if (d2 == badDay || dayEdges[d2].empty()) continue;\n\n                        auto &vec = dayEdges[d2];\n                        vector<int> trialF;\n                        int sample = min((int)vec.size(), 16);\n                        for (int t = 0; t < sample; t++) trialF.push_back(vec[rng() % vec.size()]);\n                        trialF.push_back(vec[0]);\n                        trialF.push_back(vec.back());\n                        sort(trialF.begin(), trialF.end());\n                        trialF.erase(unique(trialF.begin(), trialF.end()), trialF.end());\n\n                        for (int f : trialF) {\n                            if (!valid_swap_hard(e, f)) continue;\n                            double delta = proxy_swap_delta(e, f);\n                            if (delta > bestDelta + 5.0) continue;\n\n                            apply_swap(e, f);\n                            bool ok1 = day_connected(badDay);\n                            bool ok2 = day_connected(d2);\n                            apply_swap(e, f);\n\n                            if (ok1 && ok2 && delta < bestDelta) {\n                                bestDelta = delta;\n                                bestE = e;\n                                bestF = f;\n                            }\n                        }\n                    }\n                }\n\n                if (bestE != -1) {\n                    apply_swap(bestE, bestF);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    void proxy_local_search(double timeLimit) {\n        while (elapsed() < timeLimit) {\n            if ((rng() & 1) == 0) {\n                int a = rng() % D;\n                int b = rng() % D;\n                if (a == b) continue;\n                if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n                if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n                int e1 = pick_edge_from_day(a, true);\n                int e2 = pick_edge_from_day(b, false);\n                if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n                if (!valid_swap_hard(e1, e2)) continue;\n\n                double delta = proxy_swap_delta(e1, e2);\n                if (delta < 0.0) apply_swap(e1, e2);\n            } else {\n                int a = rng() % D;\n                int b = rng() % D;\n                if (a == b) continue;\n                if (dayEdges[a].empty()) continue;\n                if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n                int e = pick_edge_from_day(a, true);\n                if (e < 0) continue;\n                if (!valid_move_hard(e, b)) continue;\n\n                double delta = proxy_move_delta(e, b);\n                if (delta < -0.15) {\n                    int old = dayOf[e];\n                    apply_move(e, b);\n                    if (!day_connected(b)) apply_move(e, old);\n                }\n            }\n        }\n    }\n\n    ll eval_day_score(int blockedDay) {\n        vector<ll> dist;\n        ll total = 0;\n        for (int si = 0; si < L_eval; si++) {\n            dijkstra_full(landmarks[si], dist, -1, blockedDay, -1, nullptr, nullptr);\n            for (int v = 0; v < N; v++) {\n                ll dv = (dist[v] >= INF64 / 2 ? (ll)1e9 : dist[v]);\n                total += dv - origEvalDist[si][v];\n            }\n        }\n        return total;\n    }\n\n    void sampled_local_search(double timeLimit) {\n        dayScore.assign(D, 0);\n        for (int d = 0; d < D; d++) dayScore[d] = eval_day_score(d);\n\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n\n        int evalCnt = 0;\n        const int MAX_EVAL = 240;\n\n        while (elapsed() < timeLimit && evalCnt < MAX_EVAL) {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dayScore[a] > dayScore[b];\n            });\n\n            if ((rng() & 1) == 0) {\n                int topk = min(5, D);\n                int botk = min(6, D);\n                int a = ord[rng() % topk];\n\n                vector<int> targets;\n                for (int i = 0; i < botk; i++) {\n                    int b = ord[D - 1 - i];\n                    if (b != a && dayCnt[b] < K) targets.push_back(b);\n                }\n                if (targets.empty()) continue;\n                int b = targets[rng() % targets.size()];\n\n                if (dayEdges[a].empty()) continue;\n                int e = pick_edge_from_day(a, true);\n                if (e < 0) continue;\n                if (!valid_move_hard(e, b)) continue;\n\n                double pdelta = proxy_move_delta(e, b);\n                if (pdelta > 2.0 && (rng() & 3)) continue;\n\n                int old = dayOf[e];\n                apply_move(e, b);\n\n                if (!day_connected(b)) {\n                    apply_move(e, old);\n                    continue;\n                }\n\n                ll na = eval_day_score(a);\n                ll nb = eval_day_score(b);\n                evalCnt++;\n\n                ll oldScore = dayScore[a] + dayScore[b];\n                ll newScore = na + nb;\n\n                if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                    dayScore[a] = na;\n                    dayScore[b] = nb;\n                } else {\n                    apply_move(e, old);\n                }\n            } else {\n                int topk = min(5, D);\n                int botk = min(5, D);\n                int a = ord[rng() % topk];\n                int b = ord[D - 1 - (rng() % botk)];\n                if (a == b) continue;\n                if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n                int e1 = pick_edge_from_day(a, true);\n                int e2 = pick_edge_from_day(b, false);\n                if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n                if (!valid_swap_hard(e1, e2)) continue;\n\n                double pdelta = proxy_swap_delta(e1, e2);\n                if (pdelta > 3.0 && (rng() & 3)) continue;\n\n                apply_swap(e1, e2);\n\n                if (!day_connected(a) || !day_connected(b)) {\n                    apply_swap(e1, e2);\n                    continue;\n                }\n\n                ll na = eval_day_score(a);\n                ll nb = eval_day_score(b);\n                evalCnt++;\n\n                ll oldScore = dayScore[a] + dayScore[b];\n                ll newScore = na + nb;\n\n                if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                    dayScore[a] = na;\n                    dayScore[b] = nb;\n                } else {\n                    apply_swap(e1, e2);\n                }\n            }\n        }\n    }\n\n    void solve() {\n        read_input();\n        compute_two_edge_cut_conflicts();\n        compute_importance();\n\n        multi_start_initial_solution();\n\n        if (elapsed() < 1.8) repair_connectivity(1.8);\n        if (elapsed() < 2.9) proxy_local_search(2.9);\n        if (elapsed() < 3.9) repair_connectivity(3.9);\n        if (elapsed() < 5.8) sampled_local_search(5.8);\n        if (elapsed() < 5.95) repair_connectivity(5.95);\n    }\n\n    void output() {\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << (dayOf[i] + 1);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp(int nL = 0, int nR = 0) : nL(nL), nR(nR), g(nL) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        bool found = false;\n        for (int u = 0; u < nL; ++u) {\n            if (pairU[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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\nstruct ObjData {\n    int D;\n    vector<string> f, r;\n    vector<vector<int>> Xs, Ys;\n    vector<int> Xmask, Ymask;\n};\n\nstruct OccCandidate {\n    vector<char> occ;\n    int V = 0;\n    string name;\n};\n\nstruct AnalysisResult {\n    int V = 0;\n    vector<int> occLins;\n    vector<pair<int,int>> doms;\n};\n\nstruct LayerState {\n    vector<int> cells2;\n};\n\nstruct Block {\n    int size;\n    int sig;\n    vector<int> cells;\n};\n\nstruct Partition {\n    int V = 0;\n    string name;\n    vector<Block> blocks;\n    unordered_map<int, vector<int>> bySig;\n    vector<pair<int,int>> sigCounts;\n};\n\nstruct PartitionSpec {\n    string name;\n    vector<int> ops;\n    vector<int> lens;\n    array<int,3> axisRank;\n};\n\nstruct Solver {\n    int D;\n    ObjData obj[2];\n\n    vector<array<int,6>> rots;\n    unordered_map<string, int> sigId;\n    vector<int> sigSize;\n\n    Solver(int D) : D(D) {\n        init_rotations();\n    }\n\n    int lin(int x, int y, int z) const {\n        return x * D * D + y * D + z;\n    }\n\n    tuple<int,int,int> invlin(int id) const {\n        int z = id % D;\n        id /= D;\n        int y = id % D;\n        int x = id / D;\n        return {x, y, z};\n    }\n\n    int lin2(int x, int y) const {\n        return x * D + y;\n    }\n\n    static int popcnt(int x) {\n        return __builtin_popcount((unsigned)x);\n    }\n\n    void prepare_obj(int idx, const vector<string>& f, const vector<string>& r) {\n        obj[idx].D = D;\n        obj[idx].f = f;\n        obj[idx].r = r;\n        obj[idx].Xs.assign(D, {});\n        obj[idx].Ys.assign(D, {});\n        obj[idx].Xmask.assign(D, 0);\n        obj[idx].Ymask.assign(D, 0);\n\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) {\n                if (f[z][x] == '1') {\n                    obj[idx].Xs[z].push_back(x);\n                    obj[idx].Xmask[z] |= (1 << x);\n                }\n            }\n            for (int y = 0; y < D; ++y) {\n                if (r[z][y] == '1') {\n                    obj[idx].Ys[z].push_back(y);\n                    obj[idx].Ymask[z] |= (1 << y);\n                }\n            }\n        }\n    }\n\n    // ---------- canonical shape ----------\n\n    int perm_parity(const array<int,3>& p) {\n        int inv = 0;\n        for (int i = 0; i < 3; ++i) for (int j = i + 1; j < 3; ++j) {\n            if (p[i] > p[j]) ++inv;\n        }\n        return (inv % 2 == 0 ? 1 : -1);\n    }\n\n    void init_rotations() {\n        array<int,3> p = {0, 1, 2};\n        do {\n            int pp = perm_parity(p);\n            for (int s0 : {-1, 1}) for (int s1 : {-1, 1}) for (int s2 : {-1, 1}) {\n                if (pp * s0 * s1 * s2 == 1) {\n                    rots.push_back({p[0], p[1], p[2], s0, s1, s2});\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    int canonical_id(const vector<int>& cells) {\n        vector<array<int,3>> pts;\n        pts.reserve(cells.size());\n        for (int id : cells) {\n            auto [x,y,z] = invlin(id);\n            pts.push_back({x,y,z});\n        }\n\n        string best;\n        bool first = true;\n\n        for (auto rt : rots) {\n            vector<array<int,3>> q;\n            q.reserve(pts.size());\n            int mnx = INT_MAX, mny = INT_MAX, mnz = INT_MAX;\n\n            for (auto c : pts) {\n                int a[3] = {c[0], c[1], c[2]};\n                int nx = rt[3] * a[rt[0]];\n                int ny = rt[4] * a[rt[1]];\n                int nz = rt[5] * a[rt[2]];\n                q.push_back({nx, ny, nz});\n                mnx = min(mnx, nx);\n                mny = min(mny, ny);\n                mnz = min(mnz, nz);\n            }\n\n            for (auto &v : q) {\n                v[0] -= mnx;\n                v[1] -= mny;\n                v[2] -= mnz;\n            }\n            sort(q.begin(), q.end());\n\n            string s;\n            s.reserve(q.size() * 8);\n            for (auto v : q) {\n                s += to_string(v[0]);\n                s += ',';\n                s += to_string(v[1]);\n                s += ',';\n                s += to_string(v[2]);\n                s += ';';\n            }\n            if (first || s < best) {\n                first = false;\n                best = move(s);\n            }\n        }\n\n        auto it = sigId.find(best);\n        if (it != sigId.end()) return it->second;\n        int id = (int)sigSize.size();\n        sigId.emplace(best, id);\n        sigSize.push_back((int)cells.size());\n        return id;\n    }\n\n    // ---------- occupancy analysis ----------\n\n    AnalysisResult analyze_occ_for_domino(const vector<char>& occ) const {\n        AnalysisResult res;\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!occ[id]) continue;\n            res.occLins.push_back(id);\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) {\n                res.doms.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n            }\n        }\n\n        res.V = (int)res.occLins.size();\n        return res;\n    }\n\n    // ---------- cross occupancy ----------\n\n    vector<char> build_cross_occ(const ObjData& o, const vector<pair<int,int>>& centers) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            int cx = centers[z].first;\n            int cy = centers[z].second;\n            for (int x : o.Xs[z]) occ[lin(x, cy, z)] = 1;\n            for (int y : o.Ys[z]) occ[lin(cx, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    int cross_transition_score(const ObjData& o, int z, pair<int,int> a, pair<int,int> b) const {\n        int xcap = popcnt(o.Xmask[z] & o.Xmask[z+1]);\n        int ycap = popcnt(o.Ymask[z] & o.Ymask[z+1]);\n        int s = 0;\n        if (a.second == b.second) s += xcap;\n        if (a.first  == b.first ) s += ycap;\n        if (a.first == b.first && a.second == b.second) s -= 1;\n        return s;\n    }\n\n    vector<vector<pair<int,int>>> make_cross_states(const ObjData& o) const {\n        vector<vector<pair<int,int>>> states(D);\n        for (int z = 0; z < D; ++z) {\n            for (int x : o.Xs[z]) for (int y : o.Ys[z]) states[z].push_back({x, y});\n        }\n        return states;\n    }\n\n    vector<vector<int>> cross_dp_scores(const ObjData& o, const vector<vector<pair<int,int>>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1000000000);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int cand = dp[z-1][i] + cross_transition_score(o, z - 1, states[z - 1][i], states[z][j]);\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    vector<pair<int,int>> reconstruct_cross_path(const vector<vector<pair<int,int>>>& states, const vector<vector<int>>& prv, int lastIdx) const {\n        vector<pair<int,int>> centers(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            centers[z] = states[z][cur];\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n        return centers;\n    }\n\n    int local_overlap_score_cross(const ObjData& o, const vector<pair<int,int>>& centers, int z, pair<int,int> cand) const {\n        int s = 0;\n        if (z > 0) s += cross_transition_score(o, z - 1, centers[z - 1], cand);\n        if (z + 1 < D) s += cross_transition_score(o, z, cand, centers[z + 1]);\n        return s;\n    }\n\n    OccCandidate build_cross_local_from_centers(const ObjData& o, vector<pair<int,int>> centers, const string& name) const {\n        auto bestOcc = build_cross_occ(o, centers);\n        auto bestAna = analyze_occ_for_domino(bestOcc);\n\n        bool improved = true;\n        for (int pass = 0; pass < 2 && improved; ++pass) {\n            improved = false;\n            for (int z = 0; z < D; ++z) {\n                auto curCenter = centers[z];\n                int curMatch = (int)bestAna.doms.size();\n                int curTie = local_overlap_score_cross(o, centers, z, curCenter);\n\n                auto bestCenter = curCenter;\n                auto bestOccHere = bestOcc;\n                auto bestAnaHere = bestAna;\n                int bestMatch = curMatch;\n                int bestTie = curTie;\n\n                for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                    pair<int,int> cand = {x, y};\n                    if (cand == curCenter) continue;\n                    centers[z] = cand;\n                    auto occ = build_cross_occ(o, centers);\n                    auto ana = analyze_occ_for_domino(occ);\n                    int m = (int)ana.doms.size();\n                    int tie = local_overlap_score_cross(o, centers, z, cand);\n                    if (m > bestMatch || (m == bestMatch && tie > bestTie)) {\n                        bestMatch = m;\n                        bestTie = tie;\n                        bestCenter = cand;\n                        bestOccHere = move(occ);\n                        bestAnaHere = move(ana);\n                    }\n                }\n\n                centers[z] = bestCenter;\n                if (bestCenter != curCenter) {\n                    bestOcc = move(bestOccHere);\n                    bestAna = move(bestAnaHere);\n                    if (bestMatch > curMatch) improved = true;\n                }\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(bestOcc);\n        ret.V = bestAna.V;\n        ret.name = name;\n        return ret;\n    }\n\n    vector<OccCandidate> build_cross_candidates(const ObjData& o, const string& baseName, int topK = 3) const {\n        vector<OccCandidate> res;\n        auto states = make_cross_states(o);\n        vector<vector<int>> prv;\n        auto dp = cross_dp_scores(o, states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n        for (int t = 0; t < topK; ++t) {\n            auto centers = reconstruct_cross_path(states, prv, ord[t]);\n            OccCandidate c;\n            c.occ = build_cross_occ(o, centers);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = baseName + \"_dp\" + to_string(t);\n            res.push_back(move(c));\n        }\n\n        if (!ord.empty()) {\n            auto centers = reconstruct_cross_path(states, prv, ord[0]);\n            res.push_back(build_cross_local_from_centers(o, centers, baseName + \"_local\"));\n        }\n        return res;\n    }\n\n    // ---------- simple minimal occupancy ----------\n\n    vector<char> build_min_occ(const ObjData& o, bool rev) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            auto X = o.Xs[z];\n            auto Y = o.Ys[z];\n            int a = (int)X.size();\n            int b = (int)Y.size();\n\n            if (a >= b) {\n                if (rev) reverse(Y.begin(), Y.end());\n                for (int j = 0; j < b; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = b; j < a; ++j) occ[lin(X[j], Y[0], z)] = 1;\n            } else {\n                if (rev) reverse(X.begin(), X.end());\n                for (int j = 0; j < a; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = a; j < b; ++j) occ[lin(X[0], Y[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    // ---------- star occupancy ----------\n\n    vector<int> build_star_layer_cells(const ObjData& o, int z, bool anchorOnY, int anchorVal, bool rev, int offset) const {\n        vector<int> res;\n        auto X = o.Xs[z];\n        auto Y = o.Ys[z];\n        sort(X.begin(), X.end());\n        sort(Y.begin(), Y.end());\n\n        if (anchorOnY) {\n            int y0 = anchorVal;\n            vector<int> otherY;\n            for (int y : Y) if (y != y0) otherY.push_back(y);\n            if (rev) reverse(otherY.begin(), otherY.end());\n\n            int a = (int)X.size();\n            int k = (int)otherY.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int x = X[(offset + i) % a];\n                mp[x] = otherY[i];\n            }\n            for (int x : X) {\n                auto it = mp.find(x);\n                if (it == mp.end()) res.push_back(lin2(x, y0));\n                else res.push_back(lin2(x, it->second));\n            }\n        } else {\n            int x0 = anchorVal;\n            vector<int> otherX;\n            for (int x : X) if (x != x0) otherX.push_back(x);\n            if (rev) reverse(otherX.begin(), otherX.end());\n\n            int b = (int)Y.size();\n            int k = (int)otherX.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int y = Y[(offset + i) % b];\n                mp[y] = otherX[i];\n            }\n            for (int y : Y) {\n                auto it = mp.find(y);\n                if (it == mp.end()) res.push_back(lin2(x0, y));\n                else res.push_back(lin2(it->second, y));\n            }\n        }\n\n        sort(res.begin(), res.end());\n        res.erase(unique(res.begin(), res.end()), res.end());\n        return res;\n    }\n\n    vector<vector<LayerState>> make_star_states(const ObjData& o) const {\n        vector<vector<LayerState>> states(D);\n\n        for (int z = 0; z < D; ++z) {\n            set<vector<int>> seen;\n            int a = (int)o.Xs[z].size();\n            int b = (int)o.Ys[z].size();\n\n            if (a >= b) {\n                for (int y0 : o.Ys[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, a); ++off) {\n                            auto cells = build_star_layer_cells(o, z, true, y0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            } else {\n                for (int x0 : o.Xs[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, b); ++off) {\n                            auto cells = build_star_layer_cells(o, z, false, x0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            }\n        }\n        return states;\n    }\n\n    int overlap2d(const vector<int>& a, const vector<int>& b) const {\n        int i = 0, j = 0, cnt = 0;\n        while (i < (int)a.size() && j < (int)b.size()) {\n            if (a[i] == b[j]) {\n                ++cnt; ++i; ++j;\n            } else if (a[i] < b[j]) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        return cnt;\n    }\n\n    vector<vector<int>> star_dp_scores(const vector<vector<LayerState>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1000000000);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int sc = overlap2d(states[z-1][i].cells2, states[z][j].cells2);\n                    int cand = dp[z-1][i] + sc;\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    OccCandidate reconstruct_star_occ(const vector<vector<LayerState>>& states, const vector<vector<int>>& prv, int lastIdx, const string& name) const {\n        vector<int> choice(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            choice[z] = cur;\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : states[z][choice[z]].cells2) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n            }\n        }\n\n        OccCandidate ret;\n        ret.occ = move(occ);\n        ret.V = count(ret.occ.begin(), ret.occ.end(), 1);\n        ret.name = name;\n        return ret;\n    }\n\n    vector<OccCandidate> build_star_candidates(const ObjData& o, const string& baseName, int topK = 4) const {\n        vector<OccCandidate> res;\n        auto states = make_star_states(o);\n        vector<vector<int>> prv;\n        auto dp = star_dp_scores(states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n        for (int t = 0; t < topK; ++t) {\n            res.push_back(reconstruct_star_occ(states, prv, ord[t], baseName + \"_dp\" + to_string(t)));\n        }\n        return res;\n    }\n\n    // ---------- min-cover family ----------\n\n    vector<int> occ_to_layer_cells2(const vector<char>& occ, int z) const {\n        vector<int> cells;\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) {\n            if (occ[lin(x,y,z)]) cells.push_back(lin2(x,y));\n        }\n        return cells;\n    }\n\n    vector<int> solve_mincover_layer_weight(const ObjData& o, int z, const vector<int>& weight) const {\n        const auto& X = o.Xs[z];\n        const auto& Y = o.Ys[z];\n        int a = (int)X.size();\n        int b = (int)Y.size();\n\n        if (a >= b) {\n            vector<vector<int>> dp(a + 1, vector<int>(1 << b, -1000000000));\n            vector<vector<short>> prvMask(a + 1, vector<short>(1 << b, -1));\n            vector<vector<short>> prvTake(a + 1, vector<short>(1 << b, -1));\n            dp[0][0] = 0;\n\n            for (int i = 0; i < a; ++i) {\n                for (int mask = 0; mask < (1 << b); ++mask) {\n                    if (dp[i][mask] < -100000000) continue;\n                    for (int j = 0; j < b; ++j) {\n                        int cell = lin2(X[i], Y[j]);\n                        int nmask = mask | (1 << j);\n                        int cand = dp[i][mask] + weight[cell];\n                        if (cand > dp[i+1][nmask]) {\n                            dp[i+1][nmask] = cand;\n                            prvMask[i+1][nmask] = mask;\n                            prvTake[i+1][nmask] = j;\n                        }\n                    }\n                }\n            }\n\n            int mask = (1 << b) - 1;\n            vector<int> take(a);\n            for (int i = a; i >= 1; --i) {\n                take[i-1] = prvTake[i][mask];\n                mask = prvMask[i][mask];\n            }\n\n            vector<int> cells;\n            cells.reserve(a);\n            for (int i = 0; i < a; ++i) cells.push_back(lin2(X[i], Y[take[i]]));\n            sort(cells.begin(), cells.end());\n            return cells;\n        } else {\n            vector<vector<int>> dp(b + 1, vector<int>(1 << a, -1000000000));\n            vector<vector<short>> prvMask(b + 1, vector<short>(1 << a, -1));\n            vector<vector<short>> prvTake(b + 1, vector<short>(1 << a, -1));\n            dp[0][0] = 0;\n\n            for (int i = 0; i < b; ++i) {\n                for (int mask = 0; mask < (1 << a); ++mask) {\n                    if (dp[i][mask] < -100000000) continue;\n                    for (int j = 0; j < a; ++j) {\n                        int cell = lin2(X[j], Y[i]);\n                        int nmask = mask | (1 << j);\n                        int cand = dp[i][mask] + weight[cell];\n                        if (cand > dp[i+1][nmask]) {\n                            dp[i+1][nmask] = cand;\n                            prvMask[i+1][nmask] = mask;\n                            prvTake[i+1][nmask] = j;\n                        }\n                    }\n                }\n            }\n\n            int mask = (1 << a) - 1;\n            vector<int> take(b);\n            for (int i = b; i >= 1; --i) {\n                take[i-1] = prvTake[i][mask];\n                mask = prvMask[i][mask];\n            }\n\n            vector<int> cells;\n            cells.reserve(b);\n            for (int i = 0; i < b; ++i) cells.push_back(lin2(X[take[i]], Y[i]));\n            sort(cells.begin(), cells.end());\n            return cells;\n        }\n    }\n\n    vector<int> solve_mincover_layer(\n        const ObjData& o, int z,\n        const vector<int>* prevCells,\n        const vector<int>* nextCells\n    ) const {\n        vector<int> weight(D * D, 0);\n        if (prevCells) for (int v : *prevCells) weight[v] += 100;\n        if (nextCells) for (int v : *nextCells) weight[v] += 100;\n        return solve_mincover_layer_weight(o, z, weight);\n    }\n\n    vector<int> random_mincover_layer(const ObjData& o, int z, mt19937& rng) const {\n        const auto& X0 = o.Xs[z];\n        const auto& Y0 = o.Ys[z];\n        vector<int> X = X0, Y = Y0;\n        shuffle(X.begin(), X.end(), rng);\n        shuffle(Y.begin(), Y.end(), rng);\n\n        vector<int> cells;\n        if ((int)X.size() >= (int)Y.size()) {\n            int a = (int)X.size(), b = (int)Y.size();\n            cells.reserve(a);\n            for (int i = 0; i < b; ++i) cells.push_back(lin2(X[i], Y[i]));\n            uniform_int_distribution<int> dist(0, b - 1);\n            for (int i = b; i < a; ++i) cells.push_back(lin2(X[i], Y[dist(rng)]));\n        } else {\n            int a = (int)X.size(), b = (int)Y.size();\n            cells.reserve(b);\n            for (int i = 0; i < a; ++i) cells.push_back(lin2(X[i], Y[i]));\n            uniform_int_distribution<int> dist(0, a - 1);\n            for (int i = a; i < b; ++i) cells.push_back(lin2(X[dist(rng)], Y[i]));\n        }\n        sort(cells.begin(), cells.end());\n        return cells;\n    }\n\n    vector<vector<int>> init_mincover_forward(const ObjData& o) const {\n        vector<vector<int>> layers(D);\n        layers[0] = solve_mincover_layer(o, 0, nullptr, nullptr);\n        for (int z = 1; z < D; ++z) {\n            layers[z] = solve_mincover_layer(o, z, &layers[z-1], nullptr);\n        }\n        return layers;\n    }\n\n    vector<vector<int>> init_mincover_backward(const ObjData& o) const {\n        vector<vector<int>> layers(D);\n        layers[D-1] = solve_mincover_layer(o, D-1, nullptr, nullptr);\n        for (int z = D - 2; z >= 0; --z) {\n            layers[z] = solve_mincover_layer(o, z, nullptr, &layers[z+1]);\n        }\n        return layers;\n    }\n\n    vector<vector<int>> init_from_occ_layers(const vector<char>& occ) const {\n        vector<vector<int>> layers(D);\n        for (int z = 0; z < D; ++z) layers[z] = occ_to_layer_cells2(occ, z);\n        return layers;\n    }\n\n    vector<vector<int>> random_init_mincover(const ObjData& o, mt19937& rng) const {\n        vector<vector<int>> layers(D);\n        for (int z = 0; z < D; ++z) layers[z] = random_mincover_layer(o, z, rng);\n        return layers;\n    }\n\n    vector<vector<int>> local_refine_mincover(const ObjData& o, vector<vector<int>> layers, int passes) const {\n        for (int pass = 0; pass < passes; ++pass) {\n            bool changed = false;\n            for (int z = 0; z < D; ++z) {\n                const vector<int>* prev = (z > 0 ? &layers[z-1] : nullptr);\n                const vector<int>* next = (z + 1 < D ? &layers[z+1] : nullptr);\n                auto best = solve_mincover_layer(o, z, prev, next);\n                if (best != layers[z]) {\n                    layers[z] = move(best);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n        return layers;\n    }\n\n    vector<vector<int>> local_refine_mincover_random(const ObjData& o, vector<vector<int>> layers, int passes, mt19937& rng) const {\n        vector<int> order(D);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; ++pass) {\n            shuffle(order.begin(), order.end(), rng);\n            for (int z : order) {\n                vector<int> weight(D * D, 0);\n                if (z > 0) for (int v : layers[z-1]) weight[v] += 100;\n                if (z + 1 < D) for (int v : layers[z+1]) weight[v] += 100;\n                if (z > 1) for (int v : layers[z-2]) weight[v] += 20;\n                if (z + 2 < D) for (int v : layers[z+2]) weight[v] += 20;\n                for (int v : layers[z]) weight[v] += 4;\n\n                const auto& X = o.Xs[z];\n                const auto& Y = o.Ys[z];\n                for (int x : X) for (int y : Y) {\n                    weight[lin2(x, y)] += (int)(rng() % 3);\n                }\n\n                layers[z] = solve_mincover_layer_weight(o, z, weight);\n            }\n        }\n        return layers;\n    }\n\n    vector<vector<int>> global_refine_mincover(\n        const ObjData& o,\n        vector<vector<int>> layers,\n        int passes,\n        int w1,\n        int w2,\n        int wg,\n        int selfw,\n        mt19937* prng = nullptr\n    ) const {\n        vector<int> order(D);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; ++pass) {\n            vector<int> freq(D * D, 0);\n            for (int z = 0; z < D; ++z) for (int v : layers[z]) freq[v]++;\n\n            if (prng) shuffle(order.begin(), order.end(), *prng);\n\n            bool changed = false;\n            for (int z : order) {\n                for (int v : layers[z]) freq[v]--;\n\n                vector<int> weight(D * D, 0);\n                for (int v = 0; v < D * D; ++v) weight[v] += wg * freq[v];\n                if (z > 0) for (int v : layers[z-1]) weight[v] += w1;\n                if (z + 1 < D) for (int v : layers[z+1]) weight[v] += w1;\n                if (z > 1) for (int v : layers[z-2]) weight[v] += w2;\n                if (z + 2 < D) for (int v : layers[z+2]) weight[v] += w2;\n                for (int v : layers[z]) weight[v] += selfw;\n\n                if (prng) {\n                    const auto& X = o.Xs[z];\n                    const auto& Y = o.Ys[z];\n                    for (int x : X) for (int y : Y) {\n                        weight[lin2(x, y)] += (int)((*prng)() & 1U);\n                    }\n                }\n\n                auto nxt = solve_mincover_layer_weight(o, z, weight);\n                if (nxt != layers[z]) changed = true;\n                layers[z] = move(nxt);\n\n                for (int v : layers[z]) freq[v]++;\n            }\n            if (!changed) break;\n        }\n\n        return layers;\n    }\n\n    OccCandidate layers_to_occ(const vector<vector<int>>& layers, const string& name) const {\n        vector<char> occ(D * D * D, 0);\n        int V = 0;\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : layers[z]) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n                ++V;\n            }\n        }\n        return {move(occ), V, name};\n    }\n\n    uint32_t hash_obj(const ObjData& o, uint32_t salt) const {\n        uint64_t h = salt;\n        auto upd = [&](char c) {\n            h ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        for (auto& s : o.f) for (char c : s) upd(c);\n        for (auto& s : o.r) for (char c : s) upd(c);\n        return (uint32_t)(h ^ (h >> 32));\n    }\n\n    vector<OccCandidate> build_mincover_candidates(const ObjData& o, const string& baseName, const vector<OccCandidate>& extraInits) const {\n        vector<OccCandidate> res;\n        mt19937 rng(hash_obj(o, 123456789u));\n\n        auto push_layers = [&](vector<vector<int>> layers, const string& name) {\n            res.push_back(layers_to_occ(layers, name));\n        };\n\n        auto process_seed = [&](vector<vector<int>> layers, const string& name, bool addLocal, bool addGlobal) {\n            if (addLocal) {\n                auto a = local_refine_mincover(o, layers, 3);\n                push_layers(a, name + \"_loc\");\n            }\n            if (addGlobal) {\n                auto b = local_refine_mincover(o, layers, 2);\n                b = global_refine_mincover(o, move(b), 4, 90, 18, 7, 4, nullptr);\n                b = local_refine_mincover(o, move(b), 2);\n                push_layers(b, name + \"_glob\");\n            }\n        };\n\n        process_seed(init_mincover_forward(o),  baseName + \"_fw\",   true, true);\n        process_seed(init_mincover_backward(o), baseName + \"_bw\",   true, true);\n        process_seed(init_from_occ_layers(build_min_occ(o, false)), baseName + \"_A\", true, true);\n        process_seed(init_from_occ_layers(build_min_occ(o, true)),  baseName + \"_B\", true, true);\n\n        for (int i = 0; i < (int)extraInits.size() && i < 3; ++i) {\n            auto layers = init_from_occ_layers(extraInits[i].occ);\n            layers = local_refine_mincover(o, move(layers), 2);\n            layers = global_refine_mincover(o, move(layers), 4, 90, 18, 7, 4, nullptr);\n            layers = local_refine_mincover(o, move(layers), 2);\n            push_layers(layers, baseName + \"_seed\" + to_string(i));\n        }\n\n        for (int t = 0; t < 5; ++t) {\n            auto layers = random_init_mincover(o, rng);\n            layers = local_refine_mincover_random(o, move(layers), 4, rng);\n            layers = global_refine_mincover(o, move(layers), 4, 90, 18, 7, 4, &rng);\n            layers = local_refine_mincover(o, move(layers), 2);\n            push_layers(layers, baseName + \"_rnd\" + to_string(t));\n        }\n\n        return res;\n    }\n\n    vector<OccCandidate> build_occ_candidates(const ObjData& o) const {\n        vector<OccCandidate> cands;\n\n        auto add_occ = [&](OccCandidate c) {\n            for (auto& e : cands) {\n                if (e.occ == c.occ) return;\n            }\n            cands.push_back(move(c));\n        };\n\n        auto cross = build_cross_candidates(o, \"cross\", 3);\n        auto star  = build_star_candidates(o, \"star\", 4);\n\n        for (auto& c : cross) add_occ(c);\n        for (auto& c : star) add_occ(c);\n\n        vector<OccCandidate> extraSeeds;\n        for (int i = 0; i < (int)star.size() && i < 2; ++i) extraSeeds.push_back(star[i]);\n        for (int i = 0; i < (int)cross.size() && i < 2; ++i) extraSeeds.push_back(cross[i]);\n\n        for (auto& c : build_mincover_candidates(o, \"mincov\", extraSeeds)) add_occ(move(c));\n\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, false);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minA\";\n            add_occ(move(c));\n        }\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, true);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minB\";\n            add_occ(move(c));\n        }\n\n        return cands;\n    }\n\n    // ---------- partition helpers ----------\n\n    bool cell_used(const vector<char>& unused, int x, int y, int z) const {\n        if (x < 0 || x >= D || y < 0 || y >= D || z < 0 || z >= D) return false;\n        return unused[lin(x, y, z)];\n    }\n\n    void add_block(Partition& p, const vector<int>& rawCells) {\n        vector<int> cells = rawCells;\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        int sig = canonical_id(cells);\n        int idx = (int)p.blocks.size();\n        p.blocks.push_back({(int)cells.size(), sig, cells});\n        p.bySig[sig].push_back(idx);\n    }\n\n    int boundary_score_small(const vector<char>& unused, const vector<int>& cells) const {\n        static const int dx[6] = {1,-1,0,0,0,0};\n        static const int dy[6] = {0,0,1,-1,0,0};\n        static const int dz[6] = {0,0,0,0,1,-1};\n        auto inside = [&](int id) {\n            for (int v : cells) if (v == id) return true;\n            return false;\n        };\n        int score = 0;\n        for (int id : cells) {\n            auto [x,y,z] = invlin(id);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (unused[nid] && !inside(nid)) ++score;\n            }\n        }\n        return score;\n    }\n\n    bool find_best_segment_mask(\n        const vector<char>& unused,\n        int L,\n        int allowedMask,\n        const array<int,3>& axisRank,\n        vector<int>& outCells\n    ) const {\n        const int dxs[3] = {1, 0, 0};\n        const int dys[3] = {0, 1, 0};\n        const int dzs[3] = {0, 0, 1};\n\n        bool found = false;\n        int bestExt = INT_MAX, bestRank = INT_MAX, bestPerp = INT_MAX, bestKey = INT_MAX;\n        vector<int> bestCells;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (!unused[lin(x, y, z)]) continue;\n\n            for (int dir = 0; dir < 3; ++dir) {\n                int bit = 1 << dir;\n                if (!(allowedMask & bit)) continue;\n\n                int dx = dxs[dir], dy = dys[dir], dz = dzs[dir];\n                int ex = x + (L - 1) * dx;\n                int ey = y + (L - 1) * dy;\n                int ez = z + (L - 1) * dz;\n                if (ex < 0 || ex >= D || ey < 0 || ey >= D || ez < 0 || ez >= D) continue;\n\n                vector<int> cells;\n                bool ok = true;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    int id = lin(nx, ny, nz);\n                    if (!unused[id]) { ok = false; break; }\n                    cells.push_back(id);\n                }\n                if (!ok) continue;\n\n                int ext = 0;\n                if (cell_used(unused, x - dx, y - dy, z - dz)) ++ext;\n                if (cell_used(unused, ex + dx, ey + dy, ez + dz)) ++ext;\n\n                int perp = 0;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    if (dir != 0) {\n                        perp += cell_used(unused, nx - 1, ny, nz);\n                        perp += cell_used(unused, nx + 1, ny, nz);\n                    }\n                    if (dir != 1) {\n                        perp += cell_used(unused, nx, ny - 1, nz);\n                        perp += cell_used(unused, nx, ny + 1, nz);\n                    }\n                    if (dir != 2) {\n                        perp += cell_used(unused, nx, ny, nz - 1);\n                        perp += cell_used(unused, nx, ny, nz + 1);\n                    }\n                }\n\n                int rank = axisRank[dir];\n                int key = (((dir * D + x) * D + y) * D + z);\n\n                if (!found ||\n                    ext < bestExt ||\n                    (ext == bestExt && rank < bestRank) ||\n                    (ext == bestExt && rank == bestRank && perp < bestPerp) ||\n                    (ext == bestExt && rank == bestRank && perp == bestPerp && key < bestKey)) {\n                    found = true;\n                    bestExt = ext;\n                    bestRank = rank;\n                    bestPerp = perp;\n                    bestKey = key;\n                    bestCells = move(cells);\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(bestCells);\n        return true;\n    }\n\n    bool find_best_square4(const vector<char>& unused, vector<int>& outCells) const {\n        bool found = false;\n        int bestBd = INT_MAX, bestKey = INT_MAX;\n        vector<int> best;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (x + 1 < D && y + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x+1,y,z), lin(x,y+1,z), lin(x+1,y+1,z)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_small(unused, c);\n                    int key = ((((0 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n            if (x + 1 < D && z + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x+1,y,z), lin(x,y,z+1), lin(x+1,y,z+1)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_small(unused, c);\n                    int key = ((((1 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n            if (y + 1 < D && z + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x,y+1,z), lin(x,y,z+1), lin(x,y+1,z+1)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_small(unused, c);\n                    int key = ((((2 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(best);\n        return true;\n    }\n\n    bool find_best_L3(const vector<char>& unused, vector<int>& outCells) const {\n        bool found = false;\n        int bestBd = INT_MAX, bestKey = INT_MAX;\n        vector<int> best;\n\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n        const int ax[6] = {0,0,1,1,2,2};\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            int c0 = lin(x,y,z);\n            if (!unused[c0]) continue;\n            for (int d1 = 0; d1 < 6; ++d1) for (int d2 = d1 + 1; d2 < 6; ++d2) {\n                if (ax[d1] == ax[d2]) continue;\n                int x1 = x + dx[d1], y1 = y + dy[d1], z1 = z + dz[d1];\n                int x2 = x + dx[d2], y2 = y + dy[d2], z2 = z + dz[d2];\n                if (x1 < 0 || x1 >= D || y1 < 0 || y1 >= D || z1 < 0 || z1 >= D) continue;\n                if (x2 < 0 || x2 >= D || y2 < 0 || y2 >= D || z2 < 0 || z2 >= D) continue;\n                int c1 = lin(x1,y1,z1), c2 = lin(x2,y2,z2);\n                if (!unused[c1] || !unused[c2]) continue;\n                vector<int> c = {c0, c1, c2};\n                sort(c.begin(), c.end());\n                c.erase(unique(c.begin(), c.end()), c.end());\n                if ((int)c.size() != 3) continue;\n                int bd = boundary_score_small(unused, c);\n                int key = (((((d1 * 6) + d2) * D + x) * D + y) * D + z);\n                if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                    found = true; bestBd = bd; bestKey = key; best = c;\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(best);\n        return true;\n    }\n\n    void extract_components(vector<char>& unused, Partition& p) {\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        vector<char> vis(D * D * D, 0);\n        vector<int> q;\n\n        for (int s = 0; s < D * D * D; ++s) {\n            if (!unused[s] || vis[s]) continue;\n            q.clear();\n            q.push_back(s);\n            vis[s] = 1;\n            for (int qi = 0; qi < (int)q.size(); ++qi) {\n                int v = q[qi];\n                auto [x,y,z] = invlin(v);\n                for (int dir = 0; dir < 6; ++dir) {\n                    int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                    if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                    int nid = lin(nx, ny, nz);\n                    if (unused[nid] && !vis[nid]) {\n                        vis[nid] = 1;\n                        q.push_back(nid);\n                    }\n                }\n            }\n            for (int v : q) unused[v] = 0;\n            add_block(p, q);\n        }\n    }\n\n    vector<pair<int,int>> maximum_domino_pairs(const vector<char>& unused) const {\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!unused[id]) continue;\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n\n        vector<pair<int,int>> ret;\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) ret.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n        }\n        return ret;\n    }\n\n    Partition build_partition_spec(const OccCandidate& occCand, const PartitionSpec& spec) {\n        Partition p;\n        p.V = occCand.V;\n        p.name = occCand.name + \":\" + spec.name;\n\n        vector<char> unused = occCand.occ;\n\n        for (int op : spec.ops) {\n            if (op == 1 || op == 2 || op == 4 || op == 7) {\n                int mask = op;\n                for (int L : spec.lens) {\n                    if (L < 3 || L > D) continue;\n                    while (true) {\n                        vector<int> seg;\n                        if (!find_best_segment_mask(unused, L, mask, spec.axisRank, seg)) break;\n                        for (int id : seg) unused[id] = 0;\n                        add_block(p, seg);\n                    }\n                }\n            } else if (op == 8) {\n                while (true) {\n                    vector<int> sq;\n                    if (!find_best_square4(unused, sq)) break;\n                    for (int id : sq) unused[id] = 0;\n                    add_block(p, sq);\n                }\n            } else if (op == 9) {\n                while (true) {\n                    vector<int> l3;\n                    if (!find_best_L3(unused, l3)) break;\n                    for (int id : l3) unused[id] = 0;\n                    add_block(p, l3);\n                }\n            } else if (op == 10) {\n                extract_components(unused, p);\n            }\n        }\n\n        auto doms = maximum_domino_pairs(unused);\n        vector<char> used2(D * D * D, 0);\n        for (auto [a, b] : doms) {\n            if (!unused[a] || !unused[b] || used2[a] || used2[b]) continue;\n            used2[a] = used2[b] = 1;\n            add_block(p, vector<int>{a, b});\n        }\n        for (int i = 0; i < D * D * D; ++i) if (used2[i]) unused[i] = 0;\n\n        for (int i = 0; i < D * D * D; ++i) {\n            if (unused[i]) add_block(p, vector<int>{i});\n        }\n\n        p.sigCounts.reserve(p.bySig.size());\n        for (auto &kv : p.bySig) p.sigCounts.push_back({kv.first, (int)kv.second.size()});\n        sort(p.sigCounts.begin(), p.sigCounts.end());\n        return p;\n    }\n\n    vector<PartitionSpec> make_partition_specs() const {\n        vector<PartitionSpec> specs;\n        vector<int> desc, asc;\n        for (int L = D; L >= 3; --L) desc.push_back(L);\n        for (int L = 3; L <= D; ++L) asc.push_back(L);\n\n        auto add = [&](string name, vector<int> ops, const vector<int>& lens, array<int,3> rank) {\n            specs.push_back({name, ops, lens, rank});\n        };\n\n        add(\"all_zxy_desc\", {7}, desc, {1,2,0});\n        add(\"all_xyz_desc\", {7}, desc, {0,1,2});\n        add(\"all_zyx_asc\",  {7}, asc,  {1,2,0});\n        add(\"z_then_all\",   {4,7}, desc, {1,2,0});\n        add(\"x_then_all\",   {1,7}, desc, {0,2,1});\n        add(\"y_then_all\",   {2,7}, desc, {2,0,1});\n        add(\"z_only\",       {4}, desc, {1,2,0});\n        add(\"x_only\",       {1}, desc, {0,2,1});\n        add(\"y_only\",       {2}, desc, {2,0,1});\n        add(\"zxy_seq\",      {4,1,2,7}, desc, {1,2,0});\n        add(\"xyz_seq\",      {1,2,4,7}, desc, {0,1,2});\n\n        add(\"all_sq_l3\",      {7,8,9}, desc, {1,2,0});\n        add(\"sq_l3_comp\",     {8,9,10}, desc, {1,2,0});\n        add(\"all_then_comp\",  {7,10}, desc, {1,2,0});\n        add(\"z_then_sq_comp\", {4,8,10}, desc, {1,2,0});\n        add(\"comp_only\",      {10}, desc, {1,2,0});\n\n        return specs;\n    }\n\n    string partition_signature(const Partition& p) const {\n        string s;\n        s.reserve(p.sigCounts.size() * 12);\n        for (auto [sig, cnt] : p.sigCounts) {\n            s += to_string(sig);\n            s += ':';\n            s += to_string(cnt);\n            s += ';';\n        }\n        return s;\n    }\n\n    vector<Partition> build_partitions(const vector<OccCandidate>& occs) {\n        auto specs = make_partition_specs();\n        vector<Partition> ret;\n        unordered_set<string> seen;\n\n        for (auto &occ : occs) {\n            for (auto &spec : specs) {\n                Partition p = build_partition_spec(occ, spec);\n                string key = partition_signature(p);\n                if (seen.insert(key).second) ret.push_back(move(p));\n            }\n        }\n        return ret;\n    }\n\n    // ---------- scoring / output ----------\n\n    long double eval_pair(const Partition& A, const Partition& B) const {\n        long double score = (long double)A.V + (long double)B.V;\n        int i = 0, j = 0;\n        while (i < (int)A.sigCounts.size() && j < (int)B.sigCounts.size()) {\n            if (A.sigCounts[i].first == B.sigCounts[j].first) {\n                int sig = A.sigCounts[i].first;\n                int k = min(A.sigCounts[i].second, B.sigCounts[j].second);\n                int s = sigSize[sig];\n                score -= (long double)2 * s * k;\n                score += (long double)k / (long double)s;\n                ++i; ++j;\n            } else if (A.sigCounts[i].first < B.sigCounts[j].first) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        return score;\n    }\n\n    pair<vector<int>, vector<int>> build_output_arrays(const Partition& A, const Partition& B) const {\n        vector<int> outA(D * D * D, 0), outB(D * D * D, 0);\n        vector<char> usedA(A.blocks.size(), 0), usedB(B.blocks.size(), 0);\n\n        vector<tuple<int,int,int>> common;\n        int i = 0, j = 0;\n        while (i < (int)A.sigCounts.size() && j < (int)B.sigCounts.size()) {\n            if (A.sigCounts[i].first == B.sigCounts[j].first) {\n                int sig = A.sigCounts[i].first;\n                int k = min(A.sigCounts[i].second, B.sigCounts[j].second);\n                if (k > 0) common.push_back({-sigSize[sig], sig, k});\n                ++i; ++j;\n            } else if (A.sigCounts[i].first < B.sigCounts[j].first) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        sort(common.begin(), common.end());\n\n        int id = 1;\n        for (auto [negSize, sig, k] : common) {\n            const auto& va = A.bySig.at(sig);\n            const auto& vb = B.bySig.at(sig);\n            for (int t = 0; t < k; ++t) {\n                int ia = va[t];\n                int ib = vb[t];\n                usedA[ia] = 1;\n                usedB[ib] = 1;\n                for (int c : A.blocks[ia].cells) outA[c] = id;\n                for (int c : B.blocks[ib].cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        for (int bi = 0; bi < (int)A.blocks.size(); ++bi) {\n            if (usedA[bi]) continue;\n            for (int c : A.blocks[bi].cells) outA[c] = id;\n            ++id;\n        }\n        for (int bi = 0; bi < (int)B.blocks.size(); ++bi) {\n            if (usedB[bi]) continue;\n            for (int c : B.blocks[bi].cells) outB[c] = id;\n            ++id;\n        }\n\n        return {outA, outB};\n    }\n\n    void solve() {\n        auto occ1 = build_occ_candidates(obj[0]);\n        auto occ2 = build_occ_candidates(obj[1]);\n\n        auto part1 = build_partitions(occ1);\n        auto part2 = build_partitions(occ2);\n\n        int bi = 0, bj = 0;\n        long double best = 1e100L;\n\n        for (int i = 0; i < (int)part1.size(); ++i) {\n            for (int j = 0; j < (int)part2.size(); ++j) {\n                long double sc = eval_pair(part1[i], part2[j]);\n                if (sc < best) {\n                    best = sc;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        auto [out1, out2] = build_output_arrays(part1[bi], part2[bj]);\n\n        int n = 0;\n        for (int v : out1) n = max(n, v);\n        for (int v : out2) n = max(n, v);\n\n        cout << n << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out1[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out2[i];\n        }\n        cout << '\\n';\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> f1(D), r1(D), f2(D), r2(D);\n    for (int i = 0; i < D; ++i) cin >> f1[i];\n    for (int i = 0; i < D; ++i) cin >> r1[i];\n    for (int i = 0; i < D; ++i) cin >> f2[i];\n    for (int i = 0; i < D; ++i) cin >> r2[i];\n\n    Solver solver(D);\n    solver.prepare_obj(0, f1, r1);\n    solver.prepare_obj(1, f2, r2);\n    solver.solve();\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }\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;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Tree {\n    vector<char> edgeOn;\n    vector<char> vertexOn;\n};\n\nstruct Solution {\n    vector<int> P;\n    vector<char> B;\n    long long S = (1LL << 62);\n    bool feasible = false;\n    double factor = 0.0;\n};\n\nstatic const long long INF64 = (1LL << 60);\nstatic const int EXACT_TERMINAL_LIMIT = 13;\n\nint N, M, K;\nvector<int> X, Y;\nvector<Edge> edges;\nvector<int> A, Bres;\nvector<vector<pair<int,int>>> g;\n\nvector<vector<long long>> distSP;\nvector<vector<int>> parentV, parentE;\n\nvector<vector<unsigned short>> reqPow;   // 5001 => impossible\nvector<vector<pair<int,int>>> coverList; // (required_power, resident_id), sorted\n\nchrono::steady_clock::time_point g_start;\ndouble TIME_LIMIT = 1.88;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nint ceil_sqrt_ll(long long x) {\n    long long r = 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\nvoid compute_all_pairs_shortest_paths() {\n    distSP.assign(N, vector<long long>(N, INF64));\n    parentV.assign(N, vector<int>(N, -1));\n    parentE.assign(N, vector<int>(N, -1));\n\n    for (int s = 0; s < N; ++s) {\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        distSP[s][s] = 0;\n        parentV[s][s] = s;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != distSP[s][v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < distSP[s][to]) {\n                    distSP[s][to] = nd;\n                    parentV[s][to] = v;\n                    parentE[s][to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n}\n\nvoid preprocess_cover_info() {\n    reqPow.assign(N, vector<unsigned short>(K, 5001));\n    coverList.assign(N, {});\n\n    for (int v = 0; v < N; ++v) {\n        coverList[v].reserve(K);\n        for (int k = 0; k < K; ++k) {\n            long long dx = 1LL * X[v] - A[k];\n            long long dy = 1LL * Y[v] - Bres[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            if (p <= 5000) {\n                reqPow[v][k] = (unsigned short)p;\n                coverList[v].push_back({p, k});\n            }\n        }\n        sort(coverList[v].begin(), coverList[v].end());\n    }\n}\n\nlong long calc_cost(const vector<int>& P, const vector<char>& Eon) {\n    long long s = 0;\n    for (int i = 0; i < N; ++i) s += 1LL * P[i] * P[i];\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nlong long calc_tree_cost(const vector<char>& Eon) {\n    long long s = 0;\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nbool verify_solution(const vector<int>& P, const vector<char>& Eon) {\n    vector<char> vis(N, 0);\n    queue<int> q;\n    vis[0] = 1;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (auto [to, eid] : g[v]) {\n            if (!Eon[eid]) continue;\n            if (!vis[to]) {\n                vis[to] = 1;\n                q.push(to);\n            }\n        }\n    }\n\n    for (int k = 0; k < K; ++k) {\n        bool ok = false;\n        for (int v = 0; v < N; ++v) {\n            if (!vis[v]) continue;\n            if (P[v] > 0 && reqPow[v][k] <= P[v]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nvoid add_path_from_source(int s, int t, vector<char>& inTree, vector<char>& edgeOn, vector<int>& newVertices) {\n    int cur = t;\n    while (cur != s) {\n        int pe = parentE[s][cur];\n        int pv = parentV[s][cur];\n        if (pe < 0 || pv < 0) break;\n        if (!edgeOn[pe]) edgeOn[pe] = 1;\n        if (!inTree[cur]) {\n            inTree[cur] = 1;\n            newVertices.push_back(cur);\n        }\n        if (!inTree[pv]) {\n            inTree[pv] = 1;\n            newVertices.push_back(pv);\n        }\n        cur = pv;\n    }\n}\n\nvector<int> get_terminals_from_P(const vector<int>& P, vector<char>& isTerminal) {\n    isTerminal.assign(N, 0);\n    vector<int> terminals;\n    terminals.push_back(0);\n    isTerminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminals.push_back(i);\n            isTerminal[i] = 1;\n        }\n    }\n    return terminals;\n}\n\nTree finalize_tree_from_selected(const vector<char>& sel0, const vector<char>& isTerminal) {\n    vector<char> sel = sel0;\n\n    vector<vector<int>> inc(N);\n    vector<int> deg(N, 0);\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        int u = edges[e].u, v = edges[e].v;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n        deg[u]++;\n        deg[v]++;\n    }\n\n    queue<int> q;\n    for (int v = 0; v < N; ++v) {\n        if (!isTerminal[v] && deg[v] == 1) q.push(v);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (isTerminal[v] || deg[v] != 1) continue;\n\n        int remE = -1;\n        for (int e : inc[v]) if (sel[e]) {\n            remE = e;\n            break;\n        }\n        if (remE == -1) continue;\n\n        sel[remE] = 0;\n        deg[v]--;\n\n        int to = edges[remE].u ^ edges[remE].v ^ v;\n        deg[to]--;\n        if (!isTerminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    Tree tr;\n    tr.edgeOn = sel;\n    tr.vertexOn.assign(N, 0);\n    tr.vertexOn[0] = 1;\n    for (int i = 0; i < N; ++i) if (isTerminal[i]) tr.vertexOn[i] = 1;\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        tr.vertexOn[edges[e].u] = 1;\n        tr.vertexOn[edges[e].v] = 1;\n    }\n    return tr;\n}\n\nTree build_tree_from_union_edges(const vector<char>& unionOn, const vector<char>& isTerminal) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int e = 0; e < M; ++e) if (unionOn[e]) ids.push_back(e);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return edges[a].w < edges[b].w;\n    });\n\n    vector<char> sel(M, 0);\n    DSU dsu(N);\n    for (int e : ids) {\n        if (dsu.merge(edges[e].u, edges[e].v)) sel[e] = 1;\n    }\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_heuristic_tree_metric(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    int T = (int)terminals.size();\n\n    if (T >= 2) {\n        vector<long long> best(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> used(T, 0);\n        best[0] = 0;\n\n        for (int it = 0; it < T; ++it) {\n            int v = -1;\n            for (int i = 0; i < T; ++i) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                int s = terminals[par[v]];\n                int t = terminals[v];\n                int cur = t;\n                while (cur != s) {\n                    int pe = parentE[s][cur];\n                    int pv = parentV[s][cur];\n                    if (pe < 0 || pv < 0) break;\n                    unionOn[pe] = 1;\n                    cur = pv;\n                }\n            }\n\n            for (int to = 0; to < T; ++to) {\n                if (used[to]) continue;\n                long long d = distSP[terminals[v]][terminals[to]];\n                if (d < best[to]) {\n                    best[to] = d;\n                    par[to] = v;\n                }\n            }\n        }\n    }\n\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_heuristic_tree_sph(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> inTree(N, 0), unionOn(M, 0), doneTerminal(N, 0);\n    inTree[0] = 1;\n    doneTerminal[0] = 1;\n\n    int rem = 0;\n    for (int t : terminals) if (t != 0) rem++;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    while (rem > 0) {\n        int bestT = -1;\n        long long bestD = INF64;\n        for (int t : terminals) {\n            if (doneTerminal[t]) continue;\n            if (bestDist[t] < bestD) {\n                bestD = bestDist[t];\n                bestT = t;\n            }\n        }\n        if (bestT == -1) break;\n\n        vector<int> newVertices;\n        add_path_from_source(bestFrom[bestT], bestT, inTree, unionOn, newVertices);\n        if (!inTree[bestT]) {\n            inTree[bestT] = 1;\n            newVertices.push_back(bestT);\n        }\n\n        for (int v : newVertices) {\n            if (isTerminal[v] && !doneTerminal[v]) {\n                doneTerminal[v] = 1;\n                rem--;\n            }\n        }\n        if (isTerminal[bestT] && !doneTerminal[bestT]) {\n            doneTerminal[bestT] = 1;\n            rem--;\n        }\n\n        for (int nv : newVertices) {\n            for (int t : terminals) {\n                if (!doneTerminal[t] && distSP[nv][t] < bestDist[t]) {\n                    bestDist[t] = distSP[nv][t];\n                    bestFrom[t] = nv;\n                }\n            }\n        }\n    }\n\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_heuristic_tree_rootpaths(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    for (int t : terminals) if (t != 0) {\n        int cur = t;\n        while (cur != 0) {\n            int pe = parentE[0][cur];\n            int pv = parentV[0][cur];\n            if (pe < 0 || pv < 0) break;\n            unionOn[pe] = 1;\n            cur = pv;\n        }\n    }\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_heuristic_tree_best(const vector<int>& terminals, const vector<char>& isTerminal) {\n    Tree a = build_heuristic_tree_metric(terminals, isTerminal);\n    Tree b = build_heuristic_tree_sph(terminals, isTerminal);\n    Tree c = build_heuristic_tree_rootpaths(terminals, isTerminal);\n\n    long long ca = calc_tree_cost(a.edgeOn);\n    long long cb = calc_tree_cost(b.edgeOn);\n    long long cc = calc_tree_cost(c.edgeOn);\n\n    if (ca <= cb && ca <= cc) return a;\n    if (cb <= cc) return b;\n    return c;\n}\n\nTree build_exact_tree_from_terminals(const vector<int>& terminals, const vector<char>& isTerminal) {\n    int T = (int)terminals.size();\n    int SZ = 1 << T;\n    auto IDX = [&](int mask, int v) { return mask * N + v; };\n\n    vector<long long> dp(SZ * N, INF64);\n    vector<int> kind(SZ * N, -3);    // -3 unreachable, -2 path, -1 singleton, >=0 split mask\n    vector<short> prvV(SZ * N, -1);\n    vector<short> prvE(SZ * N, -1);\n\n    for (int i = 0; i < T; ++i) {\n        int id = IDX(1 << i, terminals[i]);\n        dp[id] = 0;\n        kind[id] = -1;\n    }\n\n    for (int mask = 1; mask < SZ; ++mask) {\n        if ((mask & (mask - 1)) != 0) {\n            for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n                int oth = mask ^ sub;\n                if (sub > oth) continue;\n                for (int v = 0; v < N; ++v) {\n                    long long a = dp[IDX(sub, v)];\n                    long long b = dp[IDX(oth, v)];\n                    if (a == INF64 || b == INF64) continue;\n                    long long nv = a + b;\n                    int id = IDX(mask, v);\n                    if (nv < dp[id]) {\n                        dp[id] = nv;\n                        kind[id] = sub;\n                        prvV[id] = -1;\n                        prvE[id] = -1;\n                    }\n                }\n            }\n        }\n\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int v = 0; v < N; ++v) {\n            long long d = dp[IDX(mask, v)];\n            if (d < INF64) pq.push({d, v});\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dp[IDX(mask, v)]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                int id = IDX(mask, to);\n                if (nd < dp[id]) {\n                    dp[id] = nd;\n                    kind[id] = -2;\n                    prvV[id] = (short)v;\n                    prvE[id] = (short)eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n\n    int full = SZ - 1;\n    int bestV = 0;\n    for (int v = 1; v < N; ++v) {\n        if (dp[IDX(full, v)] < dp[IDX(full, bestV)]) bestV = v;\n    }\n\n    vector<char> sel(M, 0);\n\n    function<void(int,int)> rec = [&](int mask, int v) {\n        int id = IDX(mask, v);\n        int k = kind[id];\n        if (k == -3 || k == -1) return;\n        if (k == -2) {\n            int e = prvE[id];\n            int pv = prvV[id];\n            if (e >= 0) sel[e] = 1;\n            if (pv >= 0) rec(mask, pv);\n        } else {\n            rec(k, v);\n            rec(mask ^ k, v);\n        }\n    };\n    rec(full, bestV);\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_tree_by_P(const vector<int>& P, bool useExact) {\n    vector<char> isTerminal;\n    vector<int> terminals = get_terminals_from_P(P, isTerminal);\n    if (useExact && (int)terminals.size() <= EXACT_TERMINAL_LIMIT) {\n        return build_exact_tree_from_terminals(terminals, isTerminal);\n    }\n    return build_heuristic_tree_best(terminals, isTerminal);\n}\n\nvector<int> vertices_from_tree(const Tree& tr) {\n    vector<int> vs;\n    for (int i = 0; i < N; ++i) if (tr.vertexOn[i]) vs.push_back(i);\n    return vs;\n}\n\nvoid shrink_exclusive(vector<int>& P, const vector<int>& allowed) {\n    while (true) {\n        vector<int> cnt(K, 0);\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= pv) cnt[k]++;\n            }\n        }\n\n        bool changed = false;\n        for (int v : allowed) {\n            if (P[v] <= 0) continue;\n            int oldP = P[v];\n            int need = 0;\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= oldP && cnt[k] == 1) {\n                    need = max(need, (int)reqPow[v][k]);\n                }\n            }\n            if (need < oldP) {\n                for (int k = 0; k < K; ++k) {\n                    if (reqPow[v][k] <= oldP && reqPow[v][k] > need) cnt[k]--;\n                }\n                P[v] = need;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\nvector<int> greedy_cover_fixed_set(const vector<int>& allowed, vector<int> P) {\n    vector<char> ok(N, 0);\n    for (int v : allowed) ok[v] = 1;\n    for (int i = 0; i < N; ++i) if (!ok[i]) P[i] = 0;\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    for (int v : allowed) {\n        if (P[v] <= 0) continue;\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : allowed) {\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n                if (rp > P[v] && gain > 0) {\n                    long double extra = (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : allowed) {\n                    int rp = reqPow[v][k];\n                    if (rp <= 5000 && rp > P[v]) {\n                        bestV = v;\n                        bestP = rp;\n                        break;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    shrink_exclusive(P, allowed);\n    return P;\n}\n\nvector<int> greedy_cover_with_conn(const vector<int>& candidates, vector<int> P, vector<char> inConn, double connFactor) {\n    for (int i = 0; i < N; ++i) if (P[i] > 0) inConn[i] = 1;\n    if (!inConn[0]) inConn[0] = 1;\n\n    vector<long long> bestDist(N, INF64);\n    for (int i = 0; i < N; ++i) if (inConn[i]) {\n        for (int j = 0; j < N; ++j) {\n            if (distSP[i][j] < bestDist[j]) bestDist[j] = distSP[i][j];\n        }\n    }\n\n    vector<char> covered(K, 0);\n    int rem = K;\n    for (int v = 0; v < N; ++v) if (P[v] > 0) {\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : candidates) {\n            long double conn = inConn[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : candidates) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inConn[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inConn[bestV]) {\n            inConn[bestV] = 1;\n            for (int t = 0; t < N; ++t) {\n                if (distSP[bestV][t] < bestDist[t]) bestDist[t] = distSP[bestV][t];\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    vector<int> allv = candidates;\n    sort(allv.begin(), allv.end());\n    allv.erase(unique(allv.begin(), allv.end()), allv.end());\n    shrink_exclusive(P, allv);\n    return P;\n}\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> treeVertex;\n    vector<char> treeEdge;\n};\n\nInitialState initial_connected_greedy(double connFactor) {\n    vector<int> P(N, 0);\n    vector<char> inTree(N, 0), edgeOn(M, 0);\n    inTree[0] = 1;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v = 0; v < N; ++v) {\n            long double conn = inTree[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            long double bestVal = 1e100L;\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v = 0; v < N; ++v) {\n                    int rp = reqPow[v][k];\n                    if (rp > 5000 || rp <= P[v]) continue;\n                    long double conn = inTree[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n                    long double val = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestV = v;\n                        bestP = rp;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        if (!inTree[bestV]) {\n            vector<int> newVertices;\n            add_path_from_source(bestFrom[bestV], bestV, inTree, edgeOn, newVertices);\n            if (newVertices.empty()) {\n                inTree[bestV] = 1;\n                newVertices.push_back(bestV);\n            }\n            for (int nv : newVertices) {\n                for (int t = 0; t < N; ++t) {\n                    if (distSP[nv][t] < bestDist[t]) {\n                        bestDist[t] = distSP[nv][t];\n                        bestFrom[t] = nv;\n                    }\n                }\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    return {P, inTree, edgeOn};\n}\n\npair<vector<int>, Tree> normalize_solution(vector<int> P, bool useExact, int rounds = 2) {\n    Tree tr;\n    for (int it = 0; it < rounds; ++it) {\n        tr = build_tree_by_P(P, false);\n        vector<int> allowed = vertices_from_tree(tr);\n        P = greedy_cover_fixed_set(allowed, P);\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n    tr = build_tree_by_P(P, useExact);\n    vector<int> allowed = vertices_from_tree(tr);\n    P = greedy_cover_fixed_set(allowed, P);\n    tr = build_tree_by_P(P, useExact);\n    return {P, tr};\n}\n\nvector<int> local_improve_fixed_tree_full(vector<int> P) {\n    for (int round = 0; round < 2; ++round) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1);\n        P.swap(Pnorm);\n        long long curCost = calc_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> allowed = vertices_from_tree(tr);\n        vector<int> cand;\n        for (int i = 1; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            return sa > sb;\n        });\n\n        bool improved = false;\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n\n        for (int v : cand) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n\n            vector<int> P2 = P;\n            P2[v] = 0;\n            P2 = greedy_cover_fixed_set(allowed, P2);\n            auto [P3, tr3] = normalize_solution(P2, false, 1);\n            long long cost3 = calc_cost(P3, tr3.edgeOn);\n\n            if (cost3 < bestCost && verify_solution(P3, tr3.edgeOn)) {\n                bestCost = cost3;\n                bestP = P3;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n    return P;\n}\n\nvector<int> local_improve_drop_search(vector<int> P, double globalRepairFactor) {\n    vector<int> allVertices(N);\n    iota(allVertices.begin(), allVertices.end(), 0);\n\n    for (int round = 0; round < 2; ++round) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1);\n        P.swap(Pnorm);\n        long long curCost = calc_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> cand;\n        for (int i = 1; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            if ((deg[a] == 1) != (deg[b] == 1)) return deg[a] == 1;\n            return sa > sb;\n        });\n\n        int tryCount = min<int>((int)cand.size(), elapsed_sec() < 1.2 ? 12 : 8);\n        bool improved = false;\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n\n        vector<int> treeAllowed = vertices_from_tree(tr);\n\n        for (int idx = 0; idx < tryCount; ++idx) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int v = cand[idx];\n\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_fixed_set(treeAllowed, P2);\n                auto [P3, tr3] = normalize_solution(P2, false, 1);\n                long long cost3 = calc_cost(P3, tr3.edgeOn);\n                if (cost3 < bestCost && verify_solution(P3, tr3.edgeOn)) {\n                    bestCost = cost3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n\n            if (elapsed_sec() > TIME_LIMIT) break;\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_with_conn(allVertices, P2, tr.vertexOn, globalRepairFactor);\n                auto [P3, tr3] = normalize_solution(P2, false, 1);\n                long long cost3 = calc_cost(P3, tr3.edgeOn);\n                if (cost3 < bestCost && verify_solution(P3, tr3.edgeOn)) {\n                    bestCost = cost3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n\n    return P;\n}\n\nSolution solve_attempt(double connFactor) {\n    Solution sol;\n    sol.factor = connFactor;\n\n    InitialState init = initial_connected_greedy(connFactor);\n\n    vector<int> allowed;\n    for (int i = 0; i < N; ++i) if (init.treeVertex[i]) allowed.push_back(i);\n\n    vector<int> P0(N, 0);\n    for (int v : allowed) P0[v] = init.P[v];\n    vector<int> P = greedy_cover_fixed_set(allowed, P0);\n\n    auto [P1, tr1] = normalize_solution(P, false, 2);\n    P.swap(P1);\n\n    if (elapsed_sec() <= TIME_LIMIT) {\n        P = local_improve_fixed_tree_full(P);\n    }\n    if (elapsed_sec() <= TIME_LIMIT) {\n        P = local_improve_drop_search(P, max(0.6, connFactor));\n    }\n\n    auto [Pfinal, trfinal] = normalize_solution(P, true, 2);\n    sol.P = Pfinal;\n    sol.B = trfinal.edgeOn;\n    sol.S = calc_cost(sol.P, sol.B);\n    sol.feasible = verify_solution(sol.P, sol.B);\n    if (!sol.feasible) sol.S = (1LL << 62);\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M >> K;\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; ++i) cin >> X[i] >> Y[i];\n\n    edges.resize(M);\n    g.assign(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, v, w};\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    A.resize(K);\n    Bres.resize(K);\n    for (int i = 0; i < K; ++i) cin >> A[i] >> Bres[i];\n\n    compute_all_pairs_shortest_paths();\n    preprocess_cover_info();\n\n    vector<double> factors = {0.7, 1.0, 1.4, 0.4, 2.0};\n    Solution best;\n\n    for (double f : factors) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n        Solution cur = solve_attempt(f);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    if (elapsed_sec() < 1.45) {\n        Solution cur = solve_attempt(0.0);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    if (!best.feasible) {\n        best = solve_attempt(1.0);\n    }\n\n    if (best.feasible && elapsed_sec() <= TIME_LIMIT) {\n        vector<int> P = local_improve_fixed_tree_full(best.P);\n        if (elapsed_sec() <= TIME_LIMIT) {\n            P = local_improve_drop_search(P, 1.0);\n        }\n        auto [Pf, tr] = normalize_solution(P, true, 2);\n        long long S = calc_cost(Pf, tr.edgeOn);\n        if (verify_solution(Pf, tr.edgeOn) && S < best.S) {\n            best.P = Pf;\n            best.B = tr.edgeOn;\n            best.S = S;\n            best.feasible = true;\n        }\n    }\n\n    if (!best.feasible) {\n        vector<int> allv(N);\n        iota(allv.begin(), allv.end(), 0);\n        vector<int> P = greedy_cover_fixed_set(allv, vector<int>(N, 0));\n        auto [Pf, tr] = normalize_solution(P, true, 1);\n        best.P = Pf;\n        best.B = tr.edgeOn;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (int)best.B[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr double TL = 1.92;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Board {\n    uint16_t a[N][N];\n};\n\nstruct Plan {\n    vector<int> order;\n    int cost = 0;\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} timer_global;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline long long path_weight(int row, int val) {\n    return 1024LL * (N - row) + val;\n}\n\n// Move the minimum in descendant triangle T(tx,ty) to (tx,ty).\nstatic int apply_move(Board& b, int tx, int ty, vector<Op>* ops = nullptr) {\n    int bi = tx, bj = ty;\n    int best = b.a[tx][ty];\n\n    for (int i = tx; i < N; ++i) {\n        int L = ty;\n        int R = ty + (i - tx);\n        for (int j = L; j <= R; ++j) {\n            if ((int)b.a[i][j] < best) {\n                best = b.a[i][j];\n                bi = i;\n                bj = j;\n            }\n        }\n    }\n\n    if (bi == tx && bj == ty) return 0;\n\n    static long long memo[N][N];\n    static int seen[N][N];\n    static pair<short, short> parent_[N][N];\n    static int token = 1;\n    ++token;\n\n    auto dfs = [&](auto&& self, int i, int j) -> long long {\n        if (i == tx && j == ty) return 0;\n        if (seen[i][j] == token) return memo[i][j];\n        seen[i][j] = token;\n\n        long long best_score = LLONG_MIN / 4;\n        pair<short, short> best_parent = {-1, -1};\n\n        int d = i - tx;\n        int k = j - ty;\n\n        if (k > 0) {\n            int pi = i - 1, pj = j - 1;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n        if (k < d) {\n            int pi = i - 1, pj = j;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n\n        parent_[i][j] = best_parent;\n        memo[i][j] = best_score;\n        return best_score;\n    };\n\n    dfs(dfs, bi, bj);\n\n    int cnt = 0;\n    int i = bi, j = bj;\n    while (!(i == tx && j == ty)) {\n        auto [pi, pj] = parent_[i][j];\n        swap(b.a[i][j], b.a[pi][pj]);\n        if (ops) ops->push_back({i, j, pi, pj});\n        i = pi;\n        j = pj;\n        ++cnt;\n    }\n    return cnt;\n}\n\nstatic int simulate_order(const Board& start, int x, const vector<int>& order,\n                          Board* out_board = nullptr, vector<Op>* ops = nullptr) {\n    Board cur = start;\n    int total = 0;\n    for (int y : order) total += apply_move(cur, x, y, ops);\n    if (out_board) *out_board = cur;\n    return total;\n}\n\nstatic vector<int> make_lr_order(int m, bool rev) {\n    vector<int> ord;\n    ord.reserve(m);\n    if (!rev) for (int i = 0; i < m; ++i) ord.push_back(i);\n    else for (int i = m - 1; i >= 0; --i) ord.push_back(i);\n    return ord;\n}\n\nstatic vector<int> make_center_out_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int mid = (m - 1) / 2;\n    ord.push_back(mid);\n    for (int d = 1; (int)ord.size() < m; ++d) {\n        if (mid - d >= 0) ord.push_back(mid - d);\n        if (mid + d < m) ord.push_back(mid + d);\n    }\n    return ord;\n}\n\nstatic vector<int> make_outside_in_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int l = 0, r = m - 1;\n    while (l <= r) {\n        ord.push_back(l++);\n        if (l <= r) ord.push_back(r--);\n    }\n    return ord;\n}\n\nstatic vector<int> make_even_odd_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    for (int i = 0; i < m; i += 2) ord.push_back(i);\n    for (int i = 1; i < m; i += 2) ord.push_back(i);\n    return ord;\n}\n\nstatic vector<int> make_odd_even_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    for (int i = 1; i < m; i += 2) ord.push_back(i);\n    for (int i = 0; i < m; i += 2) ord.push_back(i);\n    return ord;\n}\n\nstatic Plan greedy_row_plan(const Board& start, int x, bool one_step_lookahead, int tie_mode = 0) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        int best_y = -1;\n        int best_add = INT_MAX;\n        int best_next = INT_MAX;\n        int best_tie2 = INT_MAX;\n        Board best_board{};\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            int nextv = 0;\n            if (one_step_lookahead && step + 1 < m) {\n                nextv = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    nextv = min(nextv, c2);\n                }\n            }\n\n            int tie2 = 0;\n            if (tie_mode == 1) tie2 = abs(2 * y - x);\n            else if (tie_mode == 2) tie2 = -abs(2 * y - x);\n            else tie2 = y;\n\n            bool better = false;\n            if (add != best_add) better = (add < best_add);\n            else if (one_step_lookahead && nextv != best_next) better = (nextv < best_next);\n            else if (tie2 != best_tie2) better = (tie2 < best_tie2);\n            else if (best_y == -1 || y < best_y) better = true;\n\n            if (better) {\n                best_y = y;\n                best_add = add;\n                best_next = nextv;\n                best_tie2 = tie2;\n                best_board = tmp;\n            }\n        }\n\n        ord.push_back(best_y);\n        total += best_add;\n        mask |= (1u << best_y);\n        cur = best_board;\n    }\n\n    return {ord, total};\n}\n\nstatic Plan randomized_greedy_row_plan(const Board& start, int x, XorShift64& rng, int variant) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        struct Cand {\n            int y, add, tie1, tie2;\n            Board b;\n        };\n        vector<Cand> cands;\n        cands.reserve(m - step);\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            int tie1 = 0;\n            if (step + 1 < m) {\n                tie1 = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    tie1 = min(tie1, c2);\n                }\n            }\n\n            int tie2;\n            if (variant == 0) tie2 = y;\n            else if (variant == 1) tie2 = abs(2 * y - x);\n            else if (variant == 2) tie2 = -abs(2 * y - x);\n            else tie2 = rng.next_int(0, 1000000);\n\n            cands.push_back({y, add, tie1, tie2, tmp});\n        }\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            if (a.add != b.add) return a.add < b.add;\n            if (a.tie1 != b.tie1) return a.tie1 < b.tie1;\n            if (a.tie2 != b.tie2) return a.tie2 < b.tie2;\n            return a.y < b.y;\n        });\n\n        int rcl = min<int>(4, cands.size());\n        int pick = 0;\n        int v = rng.next_int(0, 99);\n        if (rcl == 2) {\n            pick = (v < 72 ? 0 : 1);\n        } else if (rcl == 3) {\n            if (v < 55) pick = 0;\n            else if (v < 85) pick = 1;\n            else pick = 2;\n        } else if (rcl == 4) {\n            if (v < 48) pick = 0;\n            else if (v < 76) pick = 1;\n            else if (v < 92) pick = 2;\n            else pick = 3;\n        }\n\n        ord.push_back(cands[pick].y);\n        total += cands[pick].add;\n        mask |= (1u << cands[pick].y);\n        cur = cands[pick].b;\n    }\n\n    return {ord, total};\n}\n\nstruct BeamNode {\n    Board b;\n    uint32_t mask;\n    int cost;\n    int parent;\n    int choice;\n};\n\nstatic int beam_width_for_row(int x) {\n    int m = x + 1;\n    if (m <= 6) return 320;\n    if (m <= 10) return 180;\n    if (m <= 14) return 96;\n    if (m <= 18) return 56;\n    if (m <= 22) return 36;\n    return 24;\n}\n\nstatic Plan beam_row_plan(const Board& start, int x) {\n    int m = x + 1;\n    if (m == 1) return {{0}, 0};\n\n    int W = beam_width_for_row(x);\n    vector<vector<BeamNode>> levels(m + 1);\n    levels[0].push_back(BeamNode{start, 0u, 0, -1, -1});\n\n    auto cmp = [](const BeamNode& A, const BeamNode& B) {\n        if (A.cost != B.cost) return A.cost < B.cost;\n        return A.mask < B.mask;\n    };\n\n    int done = 0;\n    for (int depth = 0; depth < m; ++depth) {\n        if (timer_global.elapsed() > TL - 0.45) break;\n\n        vector<BeamNode> cand;\n        cand.reserve(levels[depth].size() * (m - depth));\n\n        for (int idx = 0; idx < (int)levels[depth].size(); ++idx) {\n            const auto& cur = levels[depth][idx];\n            for (int y = 0; y < m; ++y) {\n                if (cur.mask & (1u << y)) continue;\n                BeamNode nxt;\n                nxt.b = cur.b;\n                int add = apply_move(nxt.b, x, y, nullptr);\n                nxt.mask = cur.mask | (1u << y);\n                nxt.cost = cur.cost + add;\n                nxt.parent = idx;\n                nxt.choice = y;\n                cand.push_back(std::move(nxt));\n            }\n        }\n\n        if ((int)cand.size() > W) {\n            nth_element(cand.begin(), cand.begin() + W, cand.end(), cmp);\n            cand.resize(W);\n        }\n        sort(cand.begin(), cand.end(), cmp);\n        levels[depth + 1] = std::move(cand);\n        done = depth + 1;\n    }\n\n    if (done == 0) return greedy_row_plan(start, x, false);\n\n    int best_idx = 0;\n    for (int i = 1; i < (int)levels[done].size(); ++i) {\n        if (levels[done][i].cost < levels[done][best_idx].cost) best_idx = i;\n    }\n\n    vector<int> ord(done);\n    int idx = best_idx;\n    for (int depth = done; depth >= 1; --depth) {\n        ord[depth - 1] = levels[depth][idx].choice;\n        idx = levels[depth][idx].parent;\n    }\n\n    if ((int)ord.size() < m) {\n        Board cur = start;\n        uint32_t mask = 0;\n        for (int y : ord) {\n            apply_move(cur, x, y, nullptr);\n            mask |= (1u << y);\n        }\n        while ((int)ord.size() < m) {\n            int best_y = -1;\n            int best_add = INT_MAX;\n            Board best_board{};\n            for (int y = 0; y < m; ++y) {\n                if (mask & (1u << y)) continue;\n                Board tmp = cur;\n                int add = apply_move(tmp, x, y, nullptr);\n                if (add < best_add) {\n                    best_add = add;\n                    best_y = y;\n                    best_board = tmp;\n                }\n            }\n            ord.push_back(best_y);\n            cur = best_board;\n            mask |= (1u << best_y);\n        }\n    }\n\n    int c = simulate_order(start, x, ord, nullptr, nullptr);\n    return {ord, c};\n}\n\nstatic Plan local_improve_plan(const Board& start, int x, Plan base, XorShift64& rng) {\n    int m = x + 1;\n    Plan cur = base;\n    cur.cost = simulate_order(start, x, cur.order, nullptr, nullptr);\n\n    if (m <= 12 && timer_global.elapsed() < TL - 0.35) {\n        bool improved = true;\n        while (improved && timer_global.elapsed() < TL - 0.28) {\n            improved = false;\n            Plan best = cur;\n\n            for (int i = 0; i < m; ++i) {\n                for (int j = i + 1; j < m; ++j) {\n                    vector<int> ord = cur.order;\n                    swap(ord[i], ord[j]);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            for (int i = 0; i < m; ++i) {\n                for (int p = 0; p < m; ++p) {\n                    if (i == p) continue;\n                    vector<int> ord = cur.order;\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            if (improved) cur = best;\n        }\n    } else {\n        int iters = (m <= 18 ? 140 : 90);\n        if (timer_global.elapsed() > TL - 0.25) iters /= 2;\n\n        Plan best = cur;\n        for (int t = 0; t < iters && timer_global.elapsed() < TL - 0.16; ++t) {\n            vector<int> ord = cur.order;\n            int tp = rng.next_int(0, 2);\n\n            if (tp == 0) {\n                int i = rng.next_int(0, m - 1);\n                int j = rng.next_int(0, m - 1);\n                if (i != j) swap(ord[i], ord[j]);\n            } else if (tp == 1) {\n                int i = rng.next_int(0, m - 1);\n                int p = rng.next_int(0, m - 1);\n                if (i != p) {\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                }\n            } else {\n                int l = rng.next_int(0, m - 1);\n                int r = rng.next_int(0, m - 1);\n                if (l > r) swap(l, r);\n                reverse(ord.begin() + l, ord.begin() + r + 1);\n            }\n\n            int c = simulate_order(start, x, ord, nullptr, nullptr);\n            if (c < cur.cost || (c == cur.cost && rng.next_int(0, 3) == 0)) {\n                cur = {ord, c};\n                if (c < best.cost) best = cur;\n            }\n        }\n        if (best.cost < cur.cost) cur = best;\n    }\n\n    return cur;\n}\n\nstatic void add_plan(vector<Plan>& out, const Board& b, int x, vector<int> ord) {\n    int c = simulate_order(b, x, ord, nullptr, nullptr);\n    out.push_back({std::move(ord), c});\n}\n\nstatic vector<Plan> dedup_sort(vector<Plan> cands) {\n    sort(cands.begin(), cands.end(), [](const Plan& a, const Plan& b) {\n        if (a.order != b.order) return a.order < b.order;\n        return a.cost < b.cost;\n    });\n    vector<Plan> uniq;\n    for (auto& p : cands) {\n        if (uniq.empty() || uniq.back().order != p.order) uniq.push_back(p);\n        else if (p.cost < uniq.back().cost) uniq.back() = p;\n    }\n    sort(uniq.begin(), uniq.end(), [](const Plan& a, const Plan& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.order < b.order;\n    });\n    return uniq;\n}\n\nstatic vector<Plan> build_main_candidates(const Board& b, int x, XorShift64& rng) {\n    int m = x + 1;\n    vector<Plan> cands;\n\n    cands.push_back(greedy_row_plan(b, x, false, 0));\n    cands.push_back(greedy_row_plan(b, x, true, 0));\n    cands.push_back(greedy_row_plan(b, x, false, 1));\n    cands.push_back(greedy_row_plan(b, x, false, 2));\n\n    add_plan(cands, b, x, make_lr_order(m, false));\n    add_plan(cands, b, x, make_lr_order(m, true));\n    add_plan(cands, b, x, make_center_out_order(m));\n    add_plan(cands, b, x, make_outside_in_order(m));\n    add_plan(cands, b, x, make_even_odd_order(m));\n    add_plan(cands, b, x, make_odd_even_order(m));\n\n    if (timer_global.elapsed() < TL - 0.55) {\n        cands.push_back(beam_row_plan(b, x));\n    }\n\n    int rand_cnt = 0;\n    double rem = TL - timer_global.elapsed();\n    if (rem > 0.90) rand_cnt = (x >= 18 ? 10 : 7);\n    else if (rem > 0.60) rand_cnt = (x >= 18 ? 7 : 5);\n    else if (rem > 0.35) rand_cnt = (x >= 18 ? 4 : 3);\n    else if (rem > 0.22) rand_cnt = 2;\n\n    for (int i = 0; i < rand_cnt; ++i) {\n        cands.push_back(randomized_greedy_row_plan(b, x, rng, i % 4));\n    }\n\n    return dedup_sort(std::move(cands));\n}\n\nstatic vector<Plan> build_proxy_candidates(const Board& b, int x) {\n    int m = x + 1;\n    vector<Plan> cands;\n    cands.push_back(greedy_row_plan(b, x, false, 0));\n    cands.push_back(greedy_row_plan(b, x, true, 0));\n    add_plan(cands, b, x, make_lr_order(m, false));\n    add_plan(cands, b, x, make_lr_order(m, true));\n    add_plan(cands, b, x, make_center_out_order(m));\n    add_plan(cands, b, x, make_outside_in_order(m));\n    add_plan(cands, b, x, make_even_odd_order(m));\n    return dedup_sort(std::move(cands));\n}\n\nstatic int cheap_row_proxy(const Board& b, int x) {\n    if (x > N - 2) return 0;\n    auto cands = build_proxy_candidates(b, x);\n    return cands.front().cost;\n}\n\nstatic int two_row_proxy(const Board& b, int x) {\n    if (x > N - 2) return 0;\n\n    auto cands = build_proxy_candidates(b, x);\n    int topk = min<int>(3, cands.size());\n\n    int ans = INT_MAX;\n    for (int i = 0; i < topk; ++i) {\n        Board after;\n        int c1 = simulate_order(b, x, cands[i].order, &after, nullptr);\n        int val = c1;\n        if (x + 1 <= N - 2 && timer_global.elapsed() < TL - 0.10) {\n            val += cheap_row_proxy(after, x + 1);\n        }\n        ans = min(ans, val);\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board board{};\n    uint64_t seed = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v;\n            cin >> v;\n            board.a[x][y] = (uint16_t)v;\n            seed ^= (uint64_t)(v + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    XorShift64 rng(seed);\n\n    vector<Op> answer;\n    answer.reserve(6000);\n\n    for (int x = 0; x < N - 1; ++x) {\n        auto candidates = build_main_candidates(board, x, rng);\n\n        vector<Plan> pool;\n        int improve_k = min<int>(4, candidates.size());\n        for (int i = 0; i < improve_k && timer_global.elapsed() < TL - 0.24; ++i) {\n            pool.push_back(local_improve_plan(board, x, candidates[i], rng));\n        }\n        for (int i = 0; i < min<int>(4, candidates.size()); ++i) pool.push_back(candidates[i]);\n\n        auto final_cands = dedup_sort(std::move(pool));\n\n        int use_k = min<int>(6, final_cands.size());\n        int best_idx = 0;\n        int best_eval = INT_MAX;\n        int best_row_cost = INT_MAX;\n\n        for (int i = 0; i < use_k; ++i) {\n            Board after;\n            int row_cost = simulate_order(board, x, final_cands[i].order, &after, nullptr);\n\n            int eval = row_cost;\n            if (x + 1 <= N - 2 && timer_global.elapsed() < TL - 0.06) {\n                eval += two_row_proxy(after, x + 1);\n            }\n\n            if (eval < best_eval || (eval == best_eval && row_cost < best_row_cost)) {\n                best_eval = eval;\n                best_row_cost = row_cost;\n                best_idx = i;\n            }\n        }\n\n        simulate_order(board, x, final_cands[best_idx].order, &board, &answer);\n    }\n\n    cout << answer.size() << '\\n';\n    for (const auto& op : answer) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXV = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int lim) { return (int)(next_u64() % (uint64_t)lim); }\n};\n\nstruct Solver {\n    int D, N, M;\n    int mid, entrance;\n\n    vector<vector<int>> nbrs;\n    array<unsigned char, MAXV> obstacle{};\n    array<unsigned char, MAXV> occupied{};\n    array<int, MAXV> label_at{};\n    array<unsigned char, MAXV> used{};\n    vector<int> free_ids;\n    int current_empty_count; // includes entrance\n\n    Solver(int D_, int N_) : D(D_), N(N_) {\n        mid = (D - 1) / 2;\n        entrance = id(0, mid);\n        nbrs.assign(D * D, {});\n        label_at.fill(-1);\n        build_neighbors();\n    }\n\n    inline int id(int i, int j) const { return i * D + j; }\n    inline int row(int v) const { return v / D; }\n    inline int col(int v) const { return v % D; }\n\n    void build_neighbors() {\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int v = id(i, j);\n                if (i > 0) nbrs[v].push_back(id(i - 1, j));\n                if (i + 1 < D) nbrs[v].push_back(id(i + 1, j));\n                if (j > 0) nbrs[v].push_back(id(i, j - 1));\n                if (j + 1 < D) nbrs[v].push_back(id(i, j + 1));\n            }\n        }\n    }\n\n    void finalize_init() {\n        free_ids.clear();\n        for (int v = 0; v < D * D; ++v) {\n            if (v == entrance) continue;\n            if (obstacle[v]) continue;\n            free_ids.push_back(v);\n        }\n        M = (int)free_ids.size();\n        current_empty_count = M + 1;\n    }\n\n    struct Analysis {\n        vector<int> legal;\n        array<int, MAXV> dist{};\n        array<int, MAXV> deg{};\n        array<int, MAXV> block_depth{};\n    };\n\n    Analysis analyze_empty(const array<unsigned char, MAXV>& occ) const {\n        Analysis A;\n        A.dist.fill(-1);\n        A.deg.fill(0);\n        A.block_depth.fill(0);\n\n        array<unsigned char, MAXV> active{};\n        for (int v = 0; v < D * D; ++v) {\n            active[v] = (!obstacle[v] && !occ[v]) ? 1 : 0;\n        }\n\n        for (int v = 0; v < D * D; ++v) {\n            if (!active[v]) continue;\n            int d = 0;\n            for (int to : nbrs[v]) if (active[to]) ++d;\n            A.deg[v] = d;\n        }\n\n        // BFS distance from entrance\n        {\n            int q[MAXV];\n            int qh = 0, qt = 0;\n            q[qt++] = entrance;\n            A.dist[entrance] = 0;\n            while (qh < qt) {\n                int v = q[qh++];\n                for (int to : nbrs[v]) {\n                    if (!active[to]) continue;\n                    if (A.dist[to] != -1) continue;\n                    A.dist[to] = A.dist[v] + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        // Tarjan articulation + biconnected components\n        array<int, MAXV> ord, low;\n        array<unsigned char, MAXV> art{};\n        ord.fill(-1);\n        low.fill(-1);\n\n        vector<pair<int,int>> estack;\n        vector<vector<int>> comps;\n        int timer = 0;\n\n        auto make_component = [&](int a, int b) {\n            vector<int> vs;\n            while (true) {\n                auto e = estack.back();\n                estack.pop_back();\n                vs.push_back(e.first);\n                vs.push_back(e.second);\n                if (e.first == a && e.second == b) break;\n            }\n            sort(vs.begin(), vs.end());\n            vs.erase(unique(vs.begin(), vs.end()), vs.end());\n            comps.push_back(move(vs));\n        };\n\n        auto dfs = [&](auto&& self, int v, int p) -> void {\n            ord[v] = low[v] = timer++;\n            int child = 0;\n            for (int to : nbrs[v]) {\n                if (!active[to]) continue;\n                if (ord[to] == -1) {\n                    ++child;\n                    estack.push_back({v, to});\n                    self(self, to, v);\n                    low[v] = min(low[v], low[to]);\n                    if (p != -1 && low[to] >= ord[v]) art[v] = 1;\n                    if (low[to] >= ord[v]) make_component(v, to);\n                } else if (to != p && ord[to] < ord[v]) {\n                    low[v] = min(low[v], ord[to]);\n                    estack.push_back({v, to});\n                }\n            }\n            if (p == -1 && child > 1) art[v] = 1;\n        };\n\n        dfs(dfs, entrance, -1);\n\n        if (!comps.empty()) {\n            vector<vector<int>> inc_comp(D * D);\n            for (int c = 0; c < (int)comps.size(); ++c) {\n                for (int v : comps[c]) inc_comp[v].push_back(c);\n            }\n\n            vector<int> art_list;\n            for (int v = 0; v < D * D; ++v) {\n                if (active[v] && art[v]) art_list.push_back(v);\n            }\n\n            int C = (int)comps.size();\n            int Acount = (int)art_list.size();\n            vector<vector<int>> bc(C + Acount);\n\n            vector<int> art_idx(D * D, -1);\n            for (int i = 0; i < Acount; ++i) art_idx[art_list[i]] = i;\n\n            for (int ai = 0; ai < Acount; ++ai) {\n                int v = art_list[ai];\n                int anode = C + ai;\n                for (int c : inc_comp[v]) {\n                    bc[anode].push_back(c);\n                    bc[c].push_back(anode);\n                }\n            }\n\n            int root_comp = -1;\n            for (int c = 0; c < C; ++c) {\n                for (int v : comps[c]) {\n                    if (v == entrance) {\n                        root_comp = c;\n                        break;\n                    }\n                }\n                if (root_comp != -1) break;\n            }\n\n            vector<int> bcdist(C + Acount, -1);\n            queue<int> q;\n            q.push(root_comp);\n            bcdist[root_comp] = 0;\n            while (!q.empty()) {\n                int x = q.front();\n                q.pop();\n                for (int y : bc[x]) {\n                    if (bcdist[y] != -1) continue;\n                    bcdist[y] = bcdist[x] + 1;\n                    q.push(y);\n                }\n            }\n\n            vector<int> comp_depth(C, 0);\n            for (int c = 0; c < C; ++c) comp_depth[c] = bcdist[c] / 2;\n\n            for (int v = 0; v < D * D; ++v) {\n                if (!active[v]) continue;\n                int bd = 0;\n                for (int c : inc_comp[v]) bd = max(bd, comp_depth[c]);\n                A.block_depth[v] = bd;\n            }\n        }\n\n        for (int v : free_ids) {\n            if (occ[v]) continue;\n            if (art[v]) continue;\n            A.legal.push_back(v);\n        }\n\n        return A;\n    }\n\n    int rank_among_remaining(const array<unsigned char, MAXV>& usd, int t) const {\n        int r = 0;\n        for (int x = 0; x < M; ++x) if (x < t && !usd[x]) ++r;\n        return r;\n    }\n\n    auto later_key(const Analysis& A, int v) const {\n        int leaf = 4 - A.deg[v];\n        int per = row(v) + abs(col(v) - mid);\n        return make_tuple(A.block_depth[v], A.dist[v], leaf, per, -v);\n    }\n\n    void sort_by_lateness(const Analysis& A, vector<int>& cells) const {\n        sort(cells.begin(), cells.end(), [&](int a, int b) {\n            return later_key(A, a) < later_key(A, b);\n        });\n    }\n\n    int target_index(int rank, int rem, int k) const {\n        if (k <= 1 || rem <= 1) return 0;\n        long long num = 1LL * rank * (k - 1) + (rem - 1) / 2;\n        return (int)(num / (rem - 1));\n    }\n\n    vector<int> estimated_output_rank(const array<unsigned char, MAXV>& occ0, int empty_count0) const {\n        array<unsigned char, MAXV> occ = occ0;\n        int rem = empty_count0 - 1;\n        vector<int> est(D * D, -1);\n\n        for (int step = 0; step < rem; ++step) {\n            Analysis A = analyze_empty(occ);\n            vector<int> legal = A.legal;\n\n            sort(legal.begin(), legal.end(), [&](int a, int b) {\n                return later_key(A, a) > later_key(A, b);\n            });\n\n            int K = min(4, (int)legal.size());\n            int best = legal[0];\n            tuple<int,int,int,int,int> bestKey = {-1,-1,-1,-1,-1};\n\n            for (int i = 0; i < K; ++i) {\n                int v = legal[i];\n                array<unsigned char, MAXV> occ2 = occ;\n                occ2[v] = 1;\n                Analysis B = analyze_empty(occ2);\n                int next_legal = (int)B.legal.size();\n                int next_bd = 0;\n                for (int w : B.legal) next_bd = max(next_bd, B.block_depth[w]);\n                int leaf = 4 - A.deg[v];\n                auto key = make_tuple(A.block_depth[v], A.dist[v], next_bd, next_legal, leaf);\n                if (i == 0 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            est[best] = rem - 1 - step;\n            occ[best] = 1;\n        }\n        return est;\n    }\n\n    int count_legal_after_place(const array<unsigned char, MAXV>& occ, int v) const {\n        array<unsigned char, MAXV> occ2 = occ;\n        occ2[v] = 1;\n        Analysis B = analyze_empty(occ2);\n        return (int)B.legal.size();\n    }\n\n    int smallest_accessible_remove(\n        const array<unsigned char, MAXV>& occ,\n        const array<int, MAXV>& lab\n    ) const {\n        array<unsigned char, MAXV> vis{};\n        array<unsigned char, MAXV> seen_occ{};\n        int q[MAXV];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n\n        int best = -1;\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (obstacle[to]) continue;\n                if (occ[to]) {\n                    if (!seen_occ[to]) {\n                        seen_occ[to] = 1;\n                        if (best == -1 || lab[to] < lab[best]) best = to;\n                    }\n                } else {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q[qt++] = to;\n                    }\n                }\n            }\n        }\n        return best;\n    }\n\n    long long inversion_count(const vector<int>& seq) const {\n        long long inv = 0;\n        int n = (int)seq.size();\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                if (seq[i] > seq[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    int cheap_policy_place(\n        const array<unsigned char, MAXV>& occ,\n        const array<unsigned char, MAXV>& usd,\n        int t,\n        int empty_count\n    ) const {\n        Analysis A = analyze_empty(occ);\n        vector<int> legal = A.legal;\n        if ((int)legal.size() == 1) return legal[0];\n\n        sort_by_lateness(A, legal);\n        int rem = empty_count - 1;\n        int r = rank_among_remaining(usd, t);\n        int idx = target_index(r, rem, (int)legal.size());\n\n        int L = max(0, idx - 1);\n        int R = min((int)legal.size() - 1, idx + 1);\n\n        int best = legal[idx];\n        tuple<int,int,int,int,int,int> bestKey = {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};\n\n        bool early = (2 * r < rem);\n\n        for (int p = L; p <= R; ++p) {\n            int v = legal[p];\n            int flex;\n            if (rem <= 22) {\n                flex = count_legal_after_place(occ, v);\n            } else {\n                flex = A.deg[v];\n            }\n            int per = row(v) + abs(col(v) - mid);\n            int dir_bd = early ? A.block_depth[v] : -A.block_depth[v];\n            int dir_ds = early ? A.dist[v] : -A.dist[v];\n            int dir_dg = early ? -A.deg[v] : A.deg[v];\n            auto key = make_tuple(abs(p - idx), dir_bd, dir_ds, dir_dg, -flex, per);\n            if (key < bestKey) {\n                best = v;\n                bestKey = key;\n            }\n        }\n\n        return best;\n    }\n\n    long long evaluate_candidate(\n        int place_v,\n        int current_t,\n        const vector<vector<int>>& perms\n    ) const {\n        long long total = 0;\n\n        for (const auto& perm : perms) {\n            array<unsigned char, MAXV> occ = occupied;\n            array<int, MAXV> lab = label_at;\n            array<unsigned char, MAXV> usd = used;\n            int empty_count = current_empty_count;\n\n            occ[place_v] = 1;\n            lab[place_v] = current_t;\n            usd[current_t] = 1;\n            --empty_count;\n\n            for (int t : perm) {\n                int v = cheap_policy_place(occ, usd, t, empty_count);\n                occ[v] = 1;\n                lab[v] = t;\n                usd[t] = 1;\n                --empty_count;\n            }\n\n            vector<int> seq;\n            seq.reserve(M);\n            for (int iter = 0; iter < M; ++iter) {\n                int v = smallest_accessible_remove(occ, lab);\n                seq.push_back(lab[v]);\n                occ[v] = 0;\n            }\n            total += inversion_count(seq);\n        }\n\n        return total;\n    }\n\n    int choose_place(int t, int step_idx) const {\n        int rem = current_empty_count - 1;\n        int r = rank_among_remaining(used, t);\n\n        Analysis A = analyze_empty(occupied);\n        vector<int> legal_sorted = A.legal;\n        sort_by_lateness(A, legal_sorted);\n\n        array<int, MAXV> pos;\n        pos.fill(-1);\n        for (int i = 0; i < (int)legal_sorted.size(); ++i) pos[legal_sorted[i]] = i;\n\n        int idx = target_index(r, rem, (int)legal_sorted.size());\n        vector<int> est = estimated_output_rank(occupied, current_empty_count);\n\n        bool early = (2 * r < rem);\n\n        vector<pair<tuple<long long,int,int,int,int,int,int>, int>> base_list;\n        base_list.reserve(A.legal.size());\n\n        for (int v : A.legal) {\n            long long diffPos = llabs((long long)pos[v] - idx);\n            long long diffEst = llabs((long long)est[v] - r);\n            int laterPenalty = (est[v] > r) ? 1 : 0;\n            int dir_bd = early ? A.block_depth[v] : -A.block_depth[v];\n            int dir_ds = early ? A.dist[v] : -A.dist[v];\n            int dir_dg = early ? -A.deg[v] : A.deg[v];\n            int per = row(v) + abs(col(v) - mid);\n            auto key = make_tuple(diffPos, diffEst, laterPenalty, dir_bd, dir_ds, dir_dg, per);\n            base_list.push_back({key, v});\n        }\n\n        sort(base_list.begin(), base_list.end(), [&](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n\n        int preK = min(6, (int)base_list.size());\n        vector<pair<tuple<long long,int,int,int,int,int,int,int>, int>> refined;\n        refined.reserve(preK);\n\n        for (int i = 0; i < preK; ++i) {\n            int v = base_list[i].second;\n            long long diffPos = llabs((long long)pos[v] - idx);\n            long long diffEst = llabs((long long)est[v] - r);\n            int laterPenalty = (est[v] > r) ? 1 : 0;\n            int nextLegal = count_legal_after_place(occupied, v);\n            int dir_bd = early ? A.block_depth[v] : -A.block_depth[v];\n            int dir_ds = early ? A.dist[v] : -A.dist[v];\n            int dir_dg = early ? -A.deg[v] : A.deg[v];\n            int per = row(v) + abs(col(v) - mid);\n            auto key = make_tuple(diffPos, diffEst, laterPenalty, -nextLegal, dir_bd, dir_ds, dir_dg, per);\n            refined.push_back({key, v});\n        }\n\n        sort(refined.begin(), refined.end(), [&](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n\n        int base_best = refined[0].second;\n\n        // Early game: avoid noisy rollout.\n        if (rem > 42 || (int)refined.size() == 1) {\n            return base_best;\n        }\n\n        // Use rollout only on a few strong structural candidates.\n        int candK = (rem > 26 ? min(3, (int)refined.size()) : min(4, (int)refined.size()));\n        vector<int> cand;\n        cand.reserve(candK);\n        for (int i = 0; i < candK; ++i) cand.push_back(refined[i].second);\n\n        vector<int> rem_labels;\n        rem_labels.reserve(rem - 1);\n        for (int x = 0; x < M; ++x) {\n            if (!used[x] && x != t) rem_labels.push_back(x);\n        }\n\n        int samples;\n        if (rem > 32) samples = 3;\n        else if (rem > 20) samples = 5;\n        else samples = 7;\n\n        uint64_t seed = 1469598103934665603ull;\n        seed ^= (uint64_t)(step_idx + 1) * 1099511628211ull;\n        seed ^= (uint64_t)(t + 13) * 1000003ull;\n        for (int v = 0; v < D * D; ++v) if (obstacle[v]) seed ^= (uint64_t)(v + 17) * 911382323ull;\n        XorShift64 rng(seed);\n\n        vector<vector<int>> perms;\n        perms.reserve(samples);\n        for (int s = 0; s < samples; ++s) {\n            vector<int> p = rem_labels;\n            for (int i = (int)p.size() - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(p[i], p[j]);\n            }\n            perms.push_back(move(p));\n        }\n\n        int best = base_best;\n        long long bestVal = -1;\n        tuple<long long,int,int,int,int,int,int,int> bestBaseKey;\n\n        for (auto& kv : refined) {\n            if (kv.second == best) {\n                bestBaseKey = kv.first;\n                break;\n            }\n        }\n\n        for (int v : cand) {\n            long long val = evaluate_candidate(v, t, perms);\n            tuple<long long,int,int,int,int,int,int,int> bkey;\n            for (auto& kv : refined) {\n                if (kv.second == v) {\n                    bkey = kv.first;\n                    break;\n                }\n            }\n            if (bestVal == -1 || val < bestVal || (val == bestVal && bkey < bestBaseKey)) {\n                best = v;\n                bestVal = val;\n                bestBaseKey = bkey;\n            }\n        }\n\n        return best;\n    }\n\n    int choose_remove_actual() const {\n        return smallest_accessible_remove(occupied, label_at);\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    Solver solver(D, N);\n\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        solver.obstacle[solver.id(r, c)] = 1;\n    }\n    solver.finalize_init();\n\n    for (int step = 0; step < solver.M; ++step) {\n        int t;\n        cin >> t;\n\n        int v = solver.choose_place(t, step);\n\n        solver.occupied[v] = 1;\n        solver.label_at[v] = t;\n        solver.used[t] = 1;\n        --solver.current_empty_count;\n\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n' << flush;\n    }\n\n    for (int k = 0; k < solver.M; ++k) {\n        int v = solver.choose_remove_actual();\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n';\n        solver.occupied[v] = 0;\n    }\n    cout << flush;\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXC = 100;\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 DeltaPack {\n    int u[16], v[16], d[16];\n    int sz = 0;\n\n    void clear() { sz = 0; }\n\n    void add(int a, int b, int val) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < sz; i++) {\n            if (u[i] == a && v[i] == b) {\n                d[i] += val;\n                return;\n            }\n        }\n        u[sz] = a;\n        v[sz] = b;\n        d[sz] = val;\n        sz++;\n    }\n};\n\nstruct Solver {\n    int n, m;\n    int orig[MAXN][MAXN];\n    bool target[MAXC + 1][MAXC + 1]{};\n\n    int g[MAXN][MAXN];\n    int bestg[MAXN][MAXN];\n\n    int area[MAXC + 1]{};\n    int adjcnt[MAXC + 1][MAXC + 1]{};\n\n    int bestZero = 0;\n\n    mt19937 rng;\n\n    static constexpr int DX[4] = {-1, 1, 0, 0};\n    static constexpr int DY[4] = {0, 0, -1, 1};\n\n    Solver() {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < n && 0 <= y && y < n;\n    }\n\n    void build_adj_from_board(int board[MAXN][MAXN], int cnt[MAXC + 1][MAXC + 1]) {\n        for (int i = 0; i <= m; i++) for (int j = 0; j <= m; j++) cnt[i][j] = 0;\n\n        auto add_pair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            cnt[a][b]++;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int c = board[i][j];\n                if (i == 0) add_pair(c, 0);\n                if (j == 0) add_pair(c, 0);\n                if (i + 1 < n) add_pair(c, board[i + 1][j]);\n                else add_pair(c, 0);\n                if (j + 1 < n) add_pair(c, board[i][j + 1]);\n                else add_pair(c, 0);\n            }\n        }\n    }\n\n    void init_target() {\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(orig, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = 0; j <= m; j++) target[i][j] = false;\n        }\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                target[i][j] = target[j][i] = (cnt[i][j] > 0);\n            }\n        }\n    }\n\n    void reset_state() {\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) g[i][j] = orig[i][j];\n        for (int c = 0; c <= m; c++) area[c] = 0;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) area[g[i][j]]++;\n        build_adj_from_board(g, adjcnt);\n        bestZero = area[0];\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = g[i][j];\n    }\n\n    bool can_remove_color_cell(int x, int y) {\n        int c = g[x][y];\n        if (c == 0) return false;\n        if (area[c] <= 1) return false;\n\n        pair<int,int> same[4];\n        int k = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == c) same[k++] = {nx, ny};\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        static int vis[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        q.push(same[0]);\n        vis[same[0].first][same[0].second] = stamp;\n        int cnt = 0;\n\n        while (!q.empty()) {\n            auto [cx, cy] = q.front();\n            q.pop();\n            cnt++;\n            if (cnt == area[c] - 1) return true;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = cx + DX[dir], ny = cy + DY[dir];\n                if (!inside(nx, ny)) continue;\n                if (nx == x && ny == y) continue;\n                if (g[nx][ny] != c) continue;\n                if (vis[nx][ny] == stamp) continue;\n                vis[nx][ny] = stamp;\n                q.push({nx, ny});\n            }\n        }\n        return cnt == area[c] - 1;\n    }\n\n    bool can_attach_zero(int x, int y) const {\n        if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return true;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == 0) return true;\n        }\n        return false;\n    }\n\n    bool check_move(int x, int y, int t, int &deltaPerim, DeltaPack &pack) {\n        int c = g[x][y];\n        if (c == 0 || c == t) return false;\n\n        if (t == 0) {\n            if (!can_attach_zero(x, y)) return false;\n        } else {\n            bool touch = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (inside(nx, ny) && g[nx][ny] == t) {\n                    touch = true;\n                    break;\n                }\n            }\n            if (!touch) return false;\n        }\n\n        pack.clear();\n        deltaPerim = 0;\n\n        auto process_side = [&](int other) {\n            deltaPerim += (t != other) - (c != other);\n            pack.add(c, other, -1);\n            pack.add(t, other, +1);\n        };\n\n        if (x > 0) process_side(g[x - 1][y]);\n        else process_side(0);\n        if (x + 1 < n) process_side(g[x + 1][y]);\n        else process_side(0);\n        if (y > 0) process_side(g[x][y - 1]);\n        else process_side(0);\n        if (y + 1 < n) process_side(g[x][y + 1]);\n        else process_side(0);\n\n        for (int i = 0; i < pack.sz; i++) {\n            int a = pack.u[i], b = pack.v[i];\n            int after = adjcnt[a][b] + pack.d[i];\n            if ((after > 0) != target[a][b]) return false;\n        }\n        return true;\n    }\n\n    void apply_move(int x, int y, int t, const DeltaPack &pack) {\n        int c = g[x][y];\n        area[c]--;\n        area[t]++;\n        g[x][y] = t;\n        for (int i = 0; i < pack.sz; i++) {\n            adjcnt[pack.u[i]][pack.v[i]] += pack.d[i];\n        }\n        if (area[0] > bestZero) {\n            bestZero = area[0];\n            for (int r = 0; r < n; r++) for (int c2 = 0; c2 < n; c2++) bestg[r][c2] = g[r][c2];\n        }\n    }\n\n    bool try_zero_move(int x, int y) {\n        if (!inside(x, y)) return false;\n        if (g[x][y] == 0) return false;\n        if (!can_remove_color_cell(x, y)) return false;\n        int dp;\n        DeltaPack pack;\n        if (!check_move(x, y, 0, dp, pack)) return false;\n        apply_move(x, y, 0, pack);\n        return true;\n    }\n\n    void harvest_local(const vector<pair<int,int>> &seeds) {\n        static int seen[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n        auto push = [&](int x, int y) {\n            if (!inside(x, y)) return;\n            if (seen[x][y] == stamp) return;\n            seen[x][y] = stamp;\n            q.push({x, y});\n        };\n\n        for (auto [x, y] : seeds) {\n            push(x, y);\n            for (int dir = 0; dir < 4; dir++) push(x + DX[dir], y + DY[dir]);\n        }\n\n        while (!q.empty()) {\n            auto [x, y] = q.front();\n            q.pop();\n            if (!inside(x, y)) continue;\n            if (g[x][y] == 0) continue;\n            if (try_zero_move(x, y)) {\n                push(x, y);\n                for (int dir = 0; dir < 4; dir++) {\n                    push(x + DX[dir], y + DY[dir]);\n                    push(x + 2 * DX[dir], y + 2 * DY[dir]);\n                }\n            }\n        }\n    }\n\n    int strict_sweep_once() {\n        vector<int> ord(n * n);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        int changes = 0;\n\n        for (int id : ord) {\n            int x = id / n, y = id % n;\n            if (g[x][y] == 0) continue;\n\n            if (try_zero_move(x, y)) {\n                changes++;\n                continue;\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int bestT = -1, bestDP = 100;\n            DeltaPack bestPack;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == g[x][y] || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                if (dp < bestDP) {\n                    bestDP = dp;\n                    bestT = t;\n                    bestPack = pack;\n                }\n            }\n\n            if (bestT != -1) {\n                bool accept = false;\n                if (bestDP < 0) accept = true;\n                else if (bestDP == 0 && (rng() & 3) == 0) accept = true;\n\n                if (accept) {\n                    apply_move(x, y, bestT, bestPack);\n                    harvest_local({{x, y}});\n                    changes++;\n                }\n            }\n        }\n\n        return changes;\n    }\n\n    void run_search(double limit_sec, const Timer &timer) {\n        reset_state();\n\n        while (timer.elapsed() < limit_sec * 0.25) {\n            int ch = strict_sweep_once();\n            if (ch == 0) break;\n        }\n\n        uniform_int_distribution<int> cellDist(0, n * n - 1);\n\n        long long iter = 0;\n        long long lastImproveIter = 0;\n        int localBest = bestZero;\n\n        while (timer.elapsed() < limit_sec) {\n            iter++;\n\n            if ((iter % 3000) == 0) {\n                int ch = strict_sweep_once();\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n                if (ch == 0 && iter - lastImproveIter > 20000) {\n                    // Mild reshuffle via another sweep; no reset, just continue.\n                    strict_sweep_once();\n                    lastImproveIter = iter;\n                }\n            }\n\n            int id = cellDist(rng);\n            int x = id / n, y = id % n;\n            int c = g[x][y];\n            if (c == 0) continue;\n\n            if ((iter & 7) == 0) {\n                if (try_zero_move(x, y)) {\n                    harvest_local({{x, y}});\n                    if (bestZero > localBest) {\n                        localBest = bestZero;\n                        lastImproveIter = iter;\n                    }\n                    continue;\n                }\n            }\n\n            if (!can_remove_color_cell(x, y)) continue;\n\n            bool used[MAXC + 1] = {};\n            int candT[4], candDP[4], candK = 0;\n            DeltaPack candPack[4];\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == c || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_move(x, y, t, dp, pack)) continue;\n\n                candT[candK] = t;\n                candDP[candK] = dp;\n                candPack[candK] = pack;\n                candK++;\n            }\n\n            if (candK == 0) continue;\n\n            int pick = 0;\n            if (candK >= 2 && (rng() % 100) < 35) {\n                pick = rng() % candK;\n            } else {\n                for (int i = 1; i < candK; i++) {\n                    if (candDP[i] < candDP[pick]) pick = i;\n                }\n            }\n\n            int dp = candDP[pick];\n            double t01 = timer.elapsed() / limit_sec;\n            double temp = 1.8 * (1.0 - t01) + 0.03 * t01;\n\n            bool accept = false;\n            if (dp <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-double(dp) / temp);\n                uint32_t rv = rng();\n                double u = (rv + 0.5) * (1.0 / 4294967296.0);\n                if (u < prob) accept = true;\n            }\n\n            if (accept) {\n                apply_move(x, y, candT[pick], candPack[pick]);\n                harvest_local({{x, y}});\n                if (bestZero > localBest) {\n                    localBest = bestZero;\n                    lastImproveIter = iter;\n                }\n            }\n        }\n    }\n\n    bool full_validate(int board[MAXN][MAXN]) {\n        int cntArea[MAXC + 1] = {};\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cntArea[board[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cntArea[c] == 0) return false;\n\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(board, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                bool cur = cnt[i][j] > 0;\n                if (cur != target[i][j]) return false;\n            }\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // Positive colors connectivity\n        vector<vector<int>> vis(n, vector<int>(n, -1));\n        for (int c = 1; c <= m; c++) {\n            pair<int,int> st = {-1, -1};\n            for (int i = 0; i < n && st.first == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (board[i][j] == c) {\n                        st = {i, j};\n                        break;\n                    }\n                }\n            }\n            if (st.first == -1) return false;\n\n            queue<pair<int,int>> q;\n            q.push(st);\n            vis[st.first][st.second] = c;\n            int got = 0;\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != c || vis[nx][ny] == c) continue;\n                    vis[nx][ny] = c;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[c]) return false;\n        }\n\n        // Zero connectivity through outside = every zero cell must connect to boundary zero.\n        if (cntArea[0] > 0) {\n            vector<vector<int>> zvis(n, vector<int>(n, 0));\n            queue<pair<int,int>> q;\n            int got = 0;\n\n            for (int i = 0; i < n; i++) {\n                for (int j : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n            for (int j = 0; j < n; j++) {\n                for (int i : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != 0 || zvis[nx][ny]) continue;\n                    zvis[nx][ny] = 1;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[0]) return false;\n        }\n\n        return true;\n    }\n\n    void solve() {\n        cin >> n >> m;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) cin >> orig[i][j];\n        }\n\n        init_target();\n\n        Timer timer;\n        const double TL = 1.92;\n\n        run_search(TL, timer);\n\n        if (!full_validate(bestg)) {\n            for (int i = 0; i < n; i++) {\n                for (int j = 0; j < n; j++) {\n                    cout << orig[i][j] << (j + 1 == n ? '\\n' : ' ');\n                }\n            }\n            return;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                cout << bestg[i][j] << (j + 1 == n ? '\\n' : ' ');\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Bin {\n    vector<int> items;\n    long double est_load = 0;\n};\n\nstruct Plan {\n    bool exact_all = false;\n    int rounds = 0;\n    int C = 0;  // exact-sorted prefix length\n    int K = 0;  // total prefix length handled with actual bin insertion\n    long double util = -1e100L;\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int lgD = 0;\n\n    vector<int> insc;\n    vector<long double> H, est_pos, pref;\n    vector<long double> est_item;\n    vector<vector<signed char>> cache; // 2 unknown, -1,0,1\n    vector<uint64_t> keyv;\n\n    static int ceil_log2_int(int x) {\n        int k = 0, p = 1;\n        while (p < x) p <<= 1, ++k;\n        return k;\n    }\n\n    static 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    int remain() const { return Q - used; }\n\n    int ask_raw(const vector<int>& L, const vector<int>& R) {\n        // Safety: should never happen after planning fix.\n        // But never exceed Q queries.\n        if (used >= Q) {\n            // Fallback behavior: impossible in correct logic.\n            // Return estimated equality-ish direction to avoid extra output.\n            return 0;\n        }\n\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        cin >> s;\n        ++used;\n        if (s == \"<\") return -1;\n        if (s == \">\") return 1;\n        return 0;\n    }\n\n    int cmp_item(int a, int b) {\n        if (cache[a][b] != 2) return cache[a][b];\n        vector<int> L{a}, R{b};\n        int c = ask_raw(L, R);\n        cache[a][b] = (signed char)c;\n        cache[b][a] = (signed char)(-c);\n        return c;\n    }\n\n    int cmp_sets(const vector<int>& A, const vector<int>& B) {\n        if (A.size() == 1 && B.size() == 1) return cmp_item(A[0], B[0]);\n        return ask_raw(A, B);\n    }\n\n    long double pref_val(int k) const {\n        k = max(0, min(k, N));\n        return pref[k];\n    }\n\n    vector<int> exact_sort_items(const vector<int>& items) {\n        // descending: heavier first\n        vector<int> sorted;\n        sorted.reserve(items.size());\n        for (int x : items) {\n            int l = 0, r = (int)sorted.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = cmp_item(x, sorted[m]);\n                if (c > 0) r = m;\n                else l = m + 1;\n            }\n            sorted.insert(sorted.begin() + l, x);\n        }\n        return sorted;\n    }\n\n    vector<int> swiss_order(int rounds) {\n        vector<int> score(N, 0);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return keyv[a] < keyv[b];\n        });\n\n        for (int r = 0; r < rounds; ++r) {\n            uint64_t salt = splitmix64(123456789ULL + 1000003ULL * r + 911ULL * N + 3571ULL * D + 8191ULL * Q);\n\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (score[a] != score[b]) return score[a] > score[b];\n                return (keyv[a] ^ salt) < (keyv[b] ^ salt);\n            });\n\n            for (int i = 0; i + 1 < N; i += 2) {\n                int a = ord[i], b = ord[i + 1];\n                int c = cmp_item(a, b);\n                if (c > 0) {\n                    ++score[a];\n                    --score[b];\n                } else if (c < 0) {\n                    ++score[b];\n                    --score[a];\n                }\n            }\n        }\n\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return keyv[a] < keyv[b];\n        });\n\n        return ord;\n    }\n\n    Plan choose_plan() {\n        Plan best;\n        int pair_round_cost = N / 2;\n\n        // Exact-all plan\n        if (insc[N] <= Q) {\n            int K = min(N, D + (Q - insc[N]) / max(1, lgD));\n            long double util =\n                1.00L * pref_val(N) +\n                0.60L * (pref_val(K) - pref_val(D));\n            best = {true, 0, N, K, util};\n        }\n\n        // Swiss + exact prefix + actual insertion prefix\n        int Rmax = (pair_round_cost == 0 ? 0 : min(8, Q / pair_round_cost));\n        for (int R = 1; R <= Rmax; ++R) {\n            int rem_after_rounds = Q - R * pair_round_cost;\n            if (rem_after_rounds < 0) continue;\n\n            long double coarse_coef = min((long double)0.68L, (long double)(0.28L + 0.07L * R));\n\n            for (int C = D; C <= N; ++C) {\n                if (insc[C] > rem_after_rounds) break;\n\n                int rem_after_exact = rem_after_rounds - insc[C];\n                int K = min(N, D + rem_after_exact / max(1, lgD));\n\n                long double util =\n                    1.00L * pref_val(C) +\n                    coarse_coef * max((long double)0.0L, pref_val(K) - pref_val(C)) +\n                    0.012L * R * pref_val(N);\n\n                if (util > best.util) {\n                    best = {false, R, C, K, util};\n                }\n            }\n        }\n\n        // Very conservative fallback\n        if (best.util < -1e50L) {\n            int C = D;\n            int K = D;\n            best = {false, 1, C, K, 0};\n        }\n\n        return best;\n    }\n\n    int compare_bins_est(const Bin& a, const Bin& b) {\n        if (a.est_load < b.est_load) return -1;\n        if (a.est_load > b.est_load) return 1;\n        return 0;\n    }\n\n    void insert_bin_sorted_maybe_actual(vector<Bin>& bins, Bin cur) {\n        if (bins.empty()) {\n            bins.push_back(std::move(cur));\n            return;\n        }\n\n        // Safety fallback: if somehow no queries remain, use estimated order.\n        if (remain() <= 0) {\n            int l = 0, r = (int)bins.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = compare_bins_est(cur, bins[m]);\n                if (c <= 0) r = m;\n                else l = m + 1;\n            }\n            bins.insert(bins.begin() + l, std::move(cur));\n            return;\n        }\n\n        int l = 0, r = (int)bins.size();\n        while (l < r) {\n            // Another safety fallback inside binary search\n            if (remain() <= 0) {\n                int ll = 0, rr = (int)bins.size();\n                while (ll < rr) {\n                    int m = (ll + rr) >> 1;\n                    int c = compare_bins_est(cur, bins[m]);\n                    if (c <= 0) rr = m;\n                    else ll = m + 1;\n                }\n                bins.insert(bins.begin() + ll, std::move(cur));\n                return;\n            }\n\n            int m = (l + r) >> 1;\n            int c = cmp_sets(cur.items, bins[m].items);\n            if (c <= 0) r = m;\n            else l = m + 1;\n        }\n        bins.insert(bins.begin() + l, std::move(cur));\n    }\n\n    vector<Bin> actual_assign_prefix(const vector<int>& order, int K) {\n        // Requires top D items of order to be exact descending.\n        vector<Bin> bins;\n        bins.reserve(D);\n        if (K < D) return bins;\n\n        // Initialize bins in ascending actual order by reversing exact top D.\n        for (int j = 0; j < D; ++j) {\n            Bin b;\n            int item = order[D - 1 - j];\n            b.items.push_back(item);\n            b.est_load = est_item[item];\n            bins.push_back(std::move(b));\n        }\n\n        for (int p = D; p < K; ++p) {\n            Bin cur = std::move(bins.front());\n            bins.erase(bins.begin());\n\n            int item = order[p];\n            cur.items.push_back(item);\n            cur.est_load += est_item[item];\n\n            insert_bin_sorted_maybe_actual(bins, std::move(cur));\n        }\n        return bins;\n    }\n\n    vector<Bin> estimated_assign_rest(const vector<int>& order, int start, vector<Bin> bins) {\n        if (bins.empty()) bins.assign(D, Bin());\n\n        for (int p = start; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_item[item];\n        }\n        return bins;\n    }\n\n    static void erase_one(vector<int>& v, int x) {\n        for (int i = 0; i < (int)v.size(); ++i) {\n            if (v[i] == x) {\n                v.erase(v.begin() + i);\n                return;\n            }\n        }\n    }\n\n    void local_improve(vector<Bin>& bins, const vector<char>& fixed) {\n        for (int iter = 0; iter < 400; ++iter) {\n            int hi = 0, lo = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load > bins[hi].est_load) hi = j;\n                if (bins[j].est_load < bins[lo].est_load) lo = j;\n            }\n            if (hi == lo) break;\n\n            long double A = bins[hi].est_load;\n            long double B = bins[lo].est_load;\n            long double best_diff = fabsl(A - B);\n\n            int type = 0; // 1 move, 2 swap\n            int bx = -1, by = -1;\n\n            if ((int)bins[hi].items.size() > 1) {\n                for (int x : bins[hi].items) {\n                    if (fixed[x]) continue;\n                    long double w = est_item[x];\n                    long double nd = fabsl((A - w) - (B + w));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 1;\n                        bx = x;\n                    }\n                }\n            }\n\n            for (int x : bins[hi].items) {\n                if (fixed[x]) continue;\n                long double wx = est_item[x];\n                for (int y : bins[lo].items) {\n                    if (fixed[y]) continue;\n                    long double wy = est_item[y];\n                    long double nd = fabsl((A - wx + wy) - (B - wy + wx));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 2;\n                        bx = x;\n                        by = y;\n                    }\n                }\n            }\n\n            if (type == 0) break;\n\n            if (type == 1) {\n                erase_one(bins[hi].items, bx);\n                bins[lo].items.push_back(bx);\n                long double w = est_item[bx];\n                bins[hi].est_load -= w;\n                bins[lo].est_load += w;\n            } else {\n                erase_one(bins[hi].items, bx);\n                erase_one(bins[lo].items, by);\n                bins[hi].items.push_back(by);\n                bins[lo].items.push_back(bx);\n                long double wx = est_item[bx];\n                long double wy = est_item[by];\n                bins[hi].est_load += wy - wx;\n                bins[lo].est_load += wx - wy;\n            }\n        }\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        lgD = ceil_log2_int(D);\n\n        insc.assign(N + 1, 0);\n        for (int k = 2; k <= N; ++k) insc[k] = insc[k - 1] + ceil_log2_int(k);\n\n        H.assign(N + 1, 0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0L / i;\n\n        est_pos.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_pos[p] = H[N] - H[p];\n\n        pref.assign(N + 1, 0);\n        for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + est_pos[i];\n\n        cache.assign(N, vector<signed char>(N, 2));\n        for (int i = 0; i < N; ++i) cache[i][i] = 0;\n\n        keyv.resize(N);\n        for (int i = 0; i < N; ++i) {\n            keyv[i] = splitmix64((uint64_t)(i + 1) * 1234567ULL + 10007ULL * N + 1000003ULL * D + 998244353ULL * Q);\n        }\n\n        Plan plan = choose_plan();\n\n        vector<int> order;\n        int C = 0;\n        int K = 0;\n\n        if (plan.exact_all) {\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            order = exact_sort_items(all);\n            C = N;\n            K = min(plan.K, N);\n        } else {\n            vector<int> coarse = swiss_order(plan.rounds);\n\n            vector<int> prefix(coarse.begin(), coarse.begin() + plan.C);\n            vector<int> exact_prefix = exact_sort_items(prefix);\n\n            order.reserve(N);\n            for (int x : exact_prefix) order.push_back(x);\n            for (int i = plan.C; i < N; ++i) order.push_back(coarse[i]);\n\n            C = plan.C;\n            K = min(plan.K, N);\n        }\n\n        est_item.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_item[order[p]] = est_pos[p];\n\n        // Extra safety: recompute a conservative feasible K from actual remaining budget.\n        // Cost of actual insertion from D..K-1 is (K-D)*lgD.\n        if (C >= D) {\n            int safeK = min(N, D + remain() / max(1, lgD));\n            K = min(K, safeK);\n        } else {\n            K = 0;\n        }\n\n        vector<char> fixed(N, 0);\n        for (int p = 0; p < C; ++p) fixed[order[p]] = 1;\n\n        vector<Bin> bins;\n        if (K >= D) {\n            bins = actual_assign_prefix(order, K);\n            bins = estimated_assign_rest(order, K, std::move(bins));\n        } else {\n            bins = estimated_assign_rest(order, 0, {});\n        }\n\n        local_improve(bins, fixed);\n\n        while (used < Q) {\n            vector<int> L{0}, R{1};\n            ask_raw(L, R);\n        }\n\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b].items) ans[x] = b;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Policy {\n    int max_chunks = 4;\n    int shortlist = 20;\n    int boundary_B = 7;\n\n    int move_pen = 14;\n    int seg_inv_w = 3;\n    int seg_adj_w = 9;\n\n    int dest_inv_w = 7;\n    int fit_w = 3;\n    int top_w = 2;\n    int size_w = 1;\n    int empty_bonus = 20;\n    int bad_fit_base = 24;\n    int bad_fit_mul = 3;\n\n    int final_move_w = 340;\n    int final_assign_w = 1;\n    int final_global_w = 6;\n    int final_future_w = 28;\n    int final_future2_w = 6;\n    int final_empty_shortage_w = 180;\n    int final_removed_bonus = 420;\n    int future_depth = 4;\n\n    int gen_pen1 = 4;\n    int gen_pen2 = 7;\n    int gen_pen3 = 9;\n    bool use_dec_runs = true;\n\n    bool try_reuse_assignment = true;\n};\n\nstruct Result {\n    long long energy;\n    vector<pair<int,int>> ops;\n};\n\nstruct Simulator {\n    int n, m;\n    vector<vector<int>> init_st;\n\n    Simulator(int n_, int m_, const vector<vector<int>>& st_) : n(n_), m(m_), init_st(st_) {}\n\n    static 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    int urgency(int x, int cur) const {\n        int d = x - cur;\n        if (d <= 10) return 5;\n        if (d <= 20) return 4;\n        if (d <= 40) return 3;\n        if (d <= 80) return 2;\n        return 1;\n    }\n\n    void remove_possible(vector<vector<int>>& st, vector<pair<int,int>>& ops, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ops.push_back({cur, 0});\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    void remove_possible_state_only(vector<vector<int>>& st, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    pair<int,int> find_box(const vector<vector<int>>& st, int v) const {\n        for (int i = 0; i < m; 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    int count_empty(const vector<vector<int>>& st) const {\n        int c = 0;\n        for (const auto& s : st) if (s.empty()) c++;\n        return c;\n    }\n\n    long long cross_inv_cost(const vector<int>& dst, const vector<int>& chunk, int cur) const {\n        long long c = 0;\n        for (int x : dst) {\n            int w = urgency(x, cur);\n            for (int y : chunk) {\n                if (x < y) c += w;\n            }\n        }\n        return c;\n    }\n\n    long long destination_local_cost(const vector<vector<int>>& st, int d, const vector<int>& chunk, int cur, const Policy& P) const {\n        int chunk_bottom = chunk.front();\n        long long c = 0;\n        c += 1LL * P.dest_inv_w * cross_inv_cost(st[d], chunk, cur);\n        c += 1LL * P.size_w * (int)st[d].size();\n\n        if (st[d].empty()) {\n            c -= P.empty_bonus;\n        } else {\n            int top = st[d].back();\n            int fit_pen = 0;\n            if (top > chunk_bottom) fit_pen = top - chunk_bottom;\n            else fit_pen = P.bad_fit_base + P.bad_fit_mul * (chunk_bottom - top);\n            c += 1LL * P.fit_w * fit_pen;\n\n            int soon = max(0, 30 - (top - cur));\n            c += 1LL * P.top_w * soon;\n        }\n        return c;\n    }\n\n    vector<pair<int,int>> decode_mask(int t, uint32_t mask) const {\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if ((mask >> i) & 1U) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n        return segs;\n    }\n\n    uint32_t encode_segs(const vector<pair<int,int>>& segs) const {\n        uint32_t mask = 0;\n        for (int i = 0; i + 1 < (int)segs.size(); i++) {\n            mask |= (1U << segs[i].second);\n        }\n        return mask;\n    }\n\n    uint32_t partition_by_metric(const vector<vector<long long>>& metric, int t, int max_chunks, int pen) const {\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> dp(max_chunks + 1, vector<long long>(t + 1, INF));\n        vector<vector<int>> prv(max_chunks + 1, vector<int>(t + 1, -1));\n        dp[0][0] = 0;\n        for (int k = 1; k <= max_chunks; k++) {\n            for (int i = 1; i <= t; i++) {\n                for (int l = 0; l < i; l++) {\n                    if (dp[k - 1][l] == INF) continue;\n                    long long cand = dp[k - 1][l] + metric[l][i - 1] + pen;\n                    if (cand < dp[k][i]) {\n                        dp[k][i] = cand;\n                        prv[k][i] = l;\n                    }\n                }\n            }\n        }\n        int best_k = 1;\n        long long best = dp[1][t];\n        for (int k = 2; k <= max_chunks; k++) {\n            if (dp[k][t] < best) {\n                best = dp[k][t];\n                best_k = k;\n            }\n        }\n        vector<pair<int,int>> rev;\n        int i = t, k = best_k;\n        while (k > 0) {\n            int l = prv[k][i];\n            rev.push_back({l, i - 1});\n            i = l;\n            --k;\n        }\n        reverse(rev.begin(), rev.end());\n        return encode_segs(rev);\n    }\n\n    uint32_t decreasing_runs_mask(const vector<int>& b, int max_chunks,\n                                  const vector<vector<long long>>& merge_metric) const {\n        int t = (int)b.size();\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if (b[i] < b[i + 1]) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n\n        while ((int)segs.size() > max_chunks) {\n            long long best_add = (1LL << 60);\n            int best_i = -1;\n            for (int i = 0; i + 1 < (int)segs.size(); i++) {\n                int l0 = segs[i].first;\n                int r0 = segs[i].second;\n                int l1 = segs[i + 1].first;\n                int r1 = segs[i + 1].second;\n                long long add = merge_metric[l0][r1] - merge_metric[l0][r0] - merge_metric[l1][r1];\n                if (add < best_add) {\n                    best_add = add;\n                    best_i = i;\n                }\n            }\n            segs[best_i].second = segs[best_i + 1].second;\n            segs.erase(segs.begin() + best_i + 1);\n        }\n        return encode_segs(segs);\n    }\n\n    bool assign_unique_destinations(\n        const vector<vector<int>>& st,\n        int src,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        vector<int>& dest_of_seg,\n        long long& min_cost\n    ) const {\n        int k = (int)segs.size();\n        vector<int> dests;\n        for (int d = 0; d < m; d++) if (d != src) dests.push_back(d);\n        int D = (int)dests.size();\n        if (k > D) return false;\n\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> cost(k, vector<long long>(D, INF));\n\n        for (int sidx = 0; sidx < k; sidx++) {\n            int l = segs[sidx].first, r = segs[sidx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n            for (int di = 0; di < D; di++) {\n                int d = dests[di];\n                cost[sidx][di] = destination_local_cost(st, d, chunk, cur, P);\n            }\n        }\n\n        int FULL = 1 << D;\n        vector<vector<long long>> dp(k + 1, vector<long long>(FULL, INF));\n        vector<vector<int>> prv_mask(k + 1, vector<int>(FULL, -1));\n        vector<vector<int>> prv_dst(k + 1, vector<int>(FULL, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < k; i++) {\n            for (int mask = 0; mask < FULL; mask++) {\n                if (dp[i][mask] == INF) continue;\n                for (int di = 0; di < D; di++) {\n                    if ((mask >> di) & 1) continue;\n                    long long cand = dp[i][mask] + cost[i][di];\n                    int nmask = mask | (1 << di);\n                    if (cand < dp[i + 1][nmask]) {\n                        dp[i + 1][nmask] = cand;\n                        prv_mask[i + 1][nmask] = mask;\n                        prv_dst[i + 1][nmask] = di;\n                    }\n                }\n            }\n        }\n\n        min_cost = INF;\n        int best_mask = -1;\n        for (int mask = 0; mask < FULL; mask++) {\n            if (dp[k][mask] < min_cost) {\n                min_cost = dp[k][mask];\n                best_mask = mask;\n            }\n        }\n        if (best_mask == -1) return false;\n\n        dest_of_seg.assign(k, -1);\n        int mask = best_mask;\n        for (int i = k; i >= 1; i--) {\n            int di = prv_dst[i][mask];\n            dest_of_seg[i - 1] = dests[di];\n            mask = prv_mask[i][mask];\n        }\n        return true;\n    }\n\n    bool greedy_reuse_assignment(\n        const vector<vector<int>>& st,\n        int src,\n        int pos,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        vector<int>& dest_of_seg,\n        long long& total_cost\n    ) const {\n        vector<vector<int>> tmp = st;\n        int k = (int)segs.size();\n        dest_of_seg.assign(k, -1);\n        total_cost = 0;\n\n        for (int idx = k - 1; idx >= 0; idx--) {\n            int l = segs[idx].first, r = segs[idx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n\n            long long best_cost = (1LL << 60);\n            int best_dst = -1;\n            for (int d = 0; d < m; d++) {\n                if (d == src) continue;\n                long long c = destination_local_cost(tmp, d, chunk, cur, P);\n                if (c < best_cost) {\n                    best_cost = c;\n                    best_dst = d;\n                }\n            }\n            if (best_dst == -1) return false;\n\n            dest_of_seg[idx] = best_dst;\n            total_cost += best_cost;\n\n            int start = pos + 1 + l;\n            vector<int> seg(tmp[src].begin() + start, tmp[src].end());\n            tmp[src].erase(tmp[src].begin() + start, tmp[src].end());\n            tmp[best_dst].insert(tmp[best_dst].end(), seg.begin(), seg.end());\n        }\n        return true;\n    }\n\n    long long global_potential(const vector<vector<int>>& st, int cur) const {\n        long long p = 0;\n        for (const auto& s : st) {\n            int h = (int)s.size();\n            for (int i = 0; i < h; i++) {\n                int w = urgency(s[i], cur);\n                for (int j = i + 1; j < h; j++) {\n                    if (s[i] < s[j]) p += w;\n                }\n            }\n        }\n        return p;\n    }\n\n    pair<long long,long long> future_blockers_score(const vector<vector<int>>& st, int cur, int depth) const {\n        long long lin = 0, quad = 0;\n        for (int z = cur; z <= n && z < cur + depth; z++) {\n            auto [si, pos] = find_box(st, z);\n            int blockers = (int)st[si].size() - pos - 1;\n            int w = depth - (z - cur);\n            lin += 1LL * w * blockers;\n            quad += 1LL * w * blockers * blockers;\n        }\n        return {lin, quad};\n    }\n\n    long long structural_cost(\n        uint32_t mask,\n        int t,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        auto segs = decode_mask(t, mask);\n        int k = (int)segs.size();\n        long long inv = 0, adj = 0;\n        for (auto [l, r] : segs) {\n            inv += invw[l][r];\n            adj += adjw[l][r];\n        }\n        return 1LL * P.move_pen * k + 1LL * P.seg_inv_w * inv + 1LL * P.seg_adj_w * adj;\n    }\n\n    vector<uint32_t> generate_candidate_masks(\n        const vector<int>& blockers,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        int t = (int)blockers.size();\n        vector<uint32_t> masks;\n        masks.push_back(0);\n\n        if (P.use_dec_runs) {\n            masks.push_back(decreasing_runs_mask(blockers, P.max_chunks, invw));\n        }\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen1));\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen2));\n        masks.push_back(partition_by_metric(adjw, t, P.max_chunks, P.gen_pen3));\n\n        if (t >= 2) {\n            vector<pair<int,int>> candB;\n            for (int i = 0; i + 1 < t; i++) {\n                int rise = max(0, blockers[i + 1] - blockers[i]);\n                int small_bonus = max(0, 120 - blockers[i + 1]);\n                int score = 4 * rise + small_bonus;\n                candB.push_back({score, i});\n            }\n            sort(candB.begin(), candB.end(), [&](auto a, auto b) {\n                if (a.first != b.first) return a.first > b.first;\n                return a.second < b.second;\n            });\n            int B = min(P.boundary_B, (int)candB.size());\n            vector<int> idxs;\n            for (int i = 0; i < B; i++) idxs.push_back(candB[i].second);\n\n            int FULL = 1 << B;\n            for (int s = 1; s < FULL; s++) {\n                if (__builtin_popcount((unsigned)s) > P.max_chunks - 1) continue;\n                uint32_t mask = 0;\n                for (int i = 0; i < B; i++) {\n                    if ((s >> i) & 1) mask |= (1U << idxs[i]);\n                }\n                masks.push_back(mask);\n            }\n        }\n\n        sort(masks.begin(), masks.end());\n        masks.erase(unique(masks.begin(), masks.end()), masks.end());\n\n        vector<pair<long long,uint32_t>> scored;\n        scored.reserve(masks.size());\n        for (uint32_t mask : masks) {\n            auto segs = decode_mask(t, mask);\n            int k = (int)segs.size();\n            if (k > P.max_chunks || k > m - 1) continue;\n            scored.push_back({structural_cost(mask, t, invw, adjw, P), mask});\n        }\n\n        sort(scored.begin(), scored.end());\n        vector<uint32_t> res;\n        int keep = min(P.shortlist, (int)scored.size());\n        for (int i = 0; i < keep; i++) res.push_back(scored[i].second);\n        return res;\n    }\n\n    struct EvalCand {\n        long long score = (1LL << 60);\n        long long assign_cost = 0;\n        vector<pair<int,int>> segs;\n        vector<int> dests;\n    };\n\n    void evaluate_assignment(\n        const vector<vector<int>>& st,\n        int cur,\n        int src,\n        int pos,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& dests,\n        long long assign_cost,\n        const Policy& P,\n        XorShift64& rng,\n        EvalCand& best\n    ) const {\n        vector<vector<int>> st2 = st;\n        int old_cur = cur;\n\n        for (int idx = (int)segs.size() - 1; idx >= 0; idx--) {\n            int l = segs[idx].first;\n            int start = pos + 1 + l;\n            int dst = dests[idx];\n\n            vector<int> seg(st2[src].begin() + start, st2[src].end());\n            st2[src].erase(st2[src].begin() + start, st2[src].end());\n            st2[dst].insert(st2[dst].end(), seg.begin(), seg.end());\n        }\n\n        int cur2 = cur;\n        remove_possible_state_only(st2, cur2);\n\n        int t = (int)st[src].size() - pos - 1;\n        int immediate_energy = t + (int)segs.size();\n        int extra_removed = (cur2 - old_cur) - 1;\n        long long gp = global_potential(st2, cur2);\n        auto [fb1, fb2] = future_blockers_score(st2, cur2, P.future_depth);\n\n        int empty_cnt = count_empty(st2);\n        int need_empty = 0;\n        if (cur2 <= 110) need_empty = 2;\n        else if (cur2 <= 170) need_empty = 1;\n        int empty_shortage = max(0, need_empty - empty_cnt);\n\n        long long score = 0;\n        score += 1LL * P.final_move_w * immediate_energy;\n        score += 1LL * P.final_assign_w * assign_cost;\n        score += 1LL * P.final_global_w * gp;\n        score += 1LL * P.final_future_w * fb1;\n        score += 1LL * P.final_future2_w * fb2;\n        score += 1LL * P.final_empty_shortage_w * empty_shortage;\n        score -= 1LL * P.final_removed_bonus * extra_removed;\n        score += rng.next_int(0, 2);\n\n        if (score < best.score) {\n            best.score = score;\n            best.assign_cost = assign_cost;\n            best.segs = segs;\n            best.dests = dests;\n        }\n    }\n\n    EvalCand choose_best_action(\n        const vector<vector<int>>& st,\n        int cur,\n        int src,\n        int pos,\n        const vector<int>& blockers,\n        const Policy& P,\n        XorShift64& rng\n    ) const {\n        int t = (int)blockers.size();\n\n        vector<vector<long long>> invw(t, vector<long long>(t, 0));\n        vector<vector<long long>> adjw(t, vector<long long>(t, 0));\n\n        for (int l = 0; l < t; l++) {\n            long long inv = 0, adj = 0;\n            for (int r = l; r < t; r++) {\n                if (r > l && blockers[r - 1] < blockers[r]) adj++;\n                for (int i = l; i < r; i++) {\n                    if (blockers[i] < blockers[r]) inv += urgency(blockers[i], cur);\n                }\n                invw[l][r] = inv;\n                adjw[l][r] = adj;\n            }\n        }\n\n        vector<uint32_t> cand_masks = generate_candidate_masks(blockers, invw, adjw, P);\n\n        EvalCand best;\n\n        for (uint32_t mask : cand_masks) {\n            auto segs = decode_mask(t, mask);\n\n            vector<int> dests;\n            long long assign_cost;\n            if (assign_unique_destinations(st, src, cur, segs, blockers, P, dests, assign_cost)) {\n                evaluate_assignment(st, cur, src, pos, segs, dests, assign_cost, P, rng, best);\n            }\n\n            if (P.try_reuse_assignment) {\n                vector<int> reuse_dests;\n                long long reuse_cost;\n                if (greedy_reuse_assignment(st, src, pos, cur, segs, blockers, P, reuse_dests, reuse_cost)) {\n                    if (reuse_dests != dests) {\n                        evaluate_assignment(st, cur, src, pos, segs, reuse_dests, reuse_cost, P, rng, best);\n                    }\n                }\n            }\n        }\n\n        if (best.segs.empty()) {\n            best.segs = {{0, t - 1}};\n            for (int d = 0; d < m; d++) {\n                if (d != src) {\n                    best.dests = {d};\n                    break;\n                }\n            }\n            best.score = 0;\n            best.assign_cost = 0;\n        }\n\n        return best;\n    }\n\n    Result run_one(const Policy& P, XorShift64& rng) const {\n        vector<vector<int>> st = init_st;\n        vector<pair<int,int>> ops;\n        long long energy = 0;\n        int cur = 1;\n\n        remove_possible(st, ops, cur);\n\n        while (cur <= n) {\n            auto [src, pos] = find_box(st, cur);\n            vector<int> blockers(st[src].begin() + pos + 1, st[src].end());\n\n            if (blockers.empty()) {\n                remove_possible(st, ops, cur);\n                continue;\n            }\n\n            EvalCand best = choose_best_action(st, cur, src, pos, blockers, P, rng);\n\n            for (int idx = (int)best.segs.size() - 1; idx >= 0; idx--) {\n                int l = best.segs[idx].first;\n                int start = pos + 1 + l;\n                int dst = best.dests[idx];\n\n                int moved = (int)st[src].size() - start;\n                energy += moved + 1;\n                ops.push_back({st[src][start], dst + 1});\n\n                vector<int> seg(st[src].begin() + start, st[src].end());\n                st[src].erase(st[src].begin() + start, st[src].end());\n                st[dst].insert(st[dst].end(), seg.begin(), seg.end());\n            }\n\n            remove_possible(st, ops, cur);\n        }\n\n        return {energy, ops};\n    }\n\n    vector<Policy> build_bases() const {\n        vector<Policy> ps;\n\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 20; p.boundary_B = 7;\n            p.move_pen = 14; p.seg_inv_w = 3; p.seg_adj_w = 9;\n            p.dest_inv_w = 7; p.fit_w = 3; p.top_w = 2; p.size_w = 1; p.empty_bonus = 20; p.bad_fit_base = 24; p.bad_fit_mul = 3;\n            p.final_move_w = 340; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 28; p.final_future2_w = 6;\n            p.final_empty_shortage_w = 180; p.final_removed_bonus = 420; p.future_depth = 4;\n            p.gen_pen1 = 4; p.gen_pen2 = 7; p.gen_pen3 = 9; p.use_dec_runs = true;\n            p.try_reuse_assignment = true;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 24; p.boundary_B = 7;\n            p.move_pen = 12; p.seg_inv_w = 2; p.seg_adj_w = 8;\n            p.dest_inv_w = 7; p.fit_w = 3; p.top_w = 2; p.size_w = 1; p.empty_bonus = 22; p.bad_fit_base = 24; p.bad_fit_mul = 3;\n            p.final_move_w = 320; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 26; p.final_future2_w = 6;\n            p.final_empty_shortage_w = 170; p.final_removed_bonus = 430; p.future_depth = 4;\n            p.gen_pen1 = 3; p.gen_pen2 = 6; p.gen_pen3 = 8; p.use_dec_runs = true;\n            p.try_reuse_assignment = true;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 18; p.boundary_B = 6;\n            p.move_pen = 16; p.seg_inv_w = 4; p.seg_adj_w = 10;\n            p.dest_inv_w = 8; p.fit_w = 4; p.top_w = 2; p.size_w = 1; p.empty_bonus = 18; p.bad_fit_base = 26; p.bad_fit_mul = 3;\n            p.final_move_w = 360; p.final_assign_w = 1; p.final_global_w = 7; p.final_future_w = 30; p.final_future2_w = 7;\n            p.final_empty_shortage_w = 220; p.final_removed_bonus = 400; p.future_depth = 4;\n            p.gen_pen1 = 5; p.gen_pen2 = 8; p.gen_pen3 = 10; p.use_dec_runs = true;\n            p.try_reuse_assignment = false;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 22; p.boundary_B = 8;\n            p.move_pen = 11; p.seg_inv_w = 2; p.seg_adj_w = 7;\n            p.dest_inv_w = 6; p.fit_w = 2; p.top_w = 1; p.size_w = 1; p.empty_bonus = 24; p.bad_fit_base = 22; p.bad_fit_mul = 2;\n            p.final_move_w = 300; p.final_assign_w = 1; p.final_global_w = 5; p.final_future_w = 24; p.final_future2_w = 5;\n            p.final_empty_shortage_w = 150; p.final_removed_bonus = 470; p.future_depth = 5;\n            p.gen_pen1 = 3; p.gen_pen2 = 5; p.gen_pen3 = 7; p.use_dec_runs = true;\n            p.try_reuse_assignment = true;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 20; p.boundary_B = 7;\n            p.move_pen = 15; p.seg_inv_w = 3; p.seg_adj_w = 11;\n            p.dest_inv_w = 8; p.fit_w = 3; p.top_w = 3; p.size_w = 1; p.empty_bonus = 18; p.bad_fit_base = 26; p.bad_fit_mul = 4;\n            p.final_move_w = 350; p.final_assign_w = 1; p.final_global_w = 7; p.final_future_w = 32; p.final_future2_w = 8;\n            p.final_empty_shortage_w = 240; p.final_removed_bonus = 390; p.future_depth = 5;\n            p.gen_pen1 = 4; p.gen_pen2 = 7; p.gen_pen3 = 10; p.use_dec_runs = false;\n            p.try_reuse_assignment = false;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 18; p.boundary_B = 8;\n            p.move_pen = 13; p.seg_inv_w = 3; p.seg_adj_w = 8;\n            p.dest_inv_w = 7; p.fit_w = 4; p.top_w = 2; p.size_w = 1; p.empty_bonus = 20; p.bad_fit_base = 23; p.bad_fit_mul = 3;\n            p.final_move_w = 330; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 29; p.final_future2_w = 7;\n            p.final_empty_shortage_w = 200; p.final_removed_bonus = 425; p.future_depth = 5;\n            p.gen_pen1 = 4; p.gen_pen2 = 6; p.gen_pen3 = 9; p.use_dec_runs = true;\n            p.try_reuse_assignment = true;\n            ps.push_back(p);\n        }\n\n        return ps;\n    }\n\n    Result solve() const {\n        uint64_t seed = 0x123456789abcdef0ULL;\n        for (const auto& s : init_st) for (int x : s) seed = splitmix64(seed ^ (uint64_t)x);\n        XorShift64 rng(seed);\n\n        vector<Policy> bases = build_bases();\n\n        Result best{(1LL << 60), {}};\n\n        auto start_time = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            auto now = chrono::steady_clock::now();\n            return chrono::duration<double, milli>(now - start_time).count();\n        };\n\n        for (const auto& p : bases) {\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        while (elapsed_ms() < 1850.0) {\n            Policy p = bases[rng.next_int(0, (int)bases.size() - 1)];\n\n            auto perturb = [&](int v, int d, int lo, int hi) {\n                return max(lo, min(hi, v + rng.next_int(-d, d)));\n            };\n\n            p.max_chunks             = perturb(p.max_chunks,             1, 3, 5);\n            p.shortlist              = perturb(p.shortlist,              4, 12, 30);\n            p.boundary_B             = perturb(p.boundary_B,             1, 5, 8);\n\n            p.move_pen               = perturb(p.move_pen,               3, 8, 20);\n            p.seg_inv_w              = perturb(p.seg_inv_w,              2, 0, 6);\n            p.seg_adj_w              = perturb(p.seg_adj_w,              3, 4, 14);\n\n            p.dest_inv_w             = perturb(p.dest_inv_w,             2, 4, 10);\n            p.fit_w                  = perturb(p.fit_w,                  1, 1, 5);\n            p.top_w                  = perturb(p.top_w,                  1, 0, 4);\n            p.size_w                 = perturb(p.size_w,                 1, 0, 3);\n            p.empty_bonus            = perturb(p.empty_bonus,            4, 10, 28);\n            p.bad_fit_base           = perturb(p.bad_fit_base,           6, 8, 35);\n            p.bad_fit_mul            = perturb(p.bad_fit_mul,            1, 1, 6);\n\n            p.final_move_w           = perturb(p.final_move_w,          40, 240, 420);\n            p.final_assign_w         = perturb(p.final_assign_w,         0, 1, 2);\n            p.final_global_w         = perturb(p.final_global_w,         2, 3, 10);\n            p.final_future_w         = perturb(p.final_future_w,         4, 18, 40);\n            p.final_future2_w        = perturb(p.final_future2_w,        2, 2, 12);\n            p.final_empty_shortage_w = perturb(p.final_empty_shortage_w,35, 80, 320);\n            p.final_removed_bonus    = perturb(p.final_removed_bonus,   50, 280, 520);\n            p.future_depth           = perturb(p.future_depth,           1, 3, 6);\n\n            p.gen_pen1               = perturb(p.gen_pen1,               2, 1, 8);\n            p.gen_pen2               = perturb(p.gen_pen2,               2, 3, 10);\n            p.gen_pen3               = perturb(p.gen_pen3,               3, 4, 12);\n            if (p.gen_pen1 > p.gen_pen2) swap(p.gen_pen1, p.gen_pen2);\n            p.use_dec_runs = (rng.next() & 1ULL) ? p.use_dec_runs : !p.use_dec_runs;\n            if ((rng.next() & 3ULL) == 0) p.try_reuse_assignment = !p.try_reuse_assignment;\n\n            auto r = run_one(p, rng);\n            if (r.energy < best.energy) best = move(r);\n        }\n\n        return best;\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>> st(m, vector<int>(n / m));\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < n / m; j++) cin >> st[i][j];\n    }\n\n    Simulator sim(n, m, st);\n    Result res = sim.solve();\n\n    for (auto [v, i] : res.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(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() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\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 EvalResult {\n    long double score;\n    vector<long long> contrib;\n    vector<int> cnt_in;\n};\n\nstruct Candidate {\n    vector<int> wps;   // canonicalized waypoints\n    vector<int> seq;   // realized route\n    long double score = 1e100L;\n};\n\nstatic constexpr long double INF_SCORE = 1e100L;\n\nint N, Vn;\nvector<vector<int>> g;\nvector<int> dirt;\nvector<double> potv;\n\nvector<uint16_t> distmat;\nvector<uint16_t> parmat;\n\ninline int VID(int r, int c) { return r * N + c; }\ninline uint16_t& DIST(int s, int t) { return distmat[s * Vn + t]; }\ninline uint16_t& PAR(int s, int t) { return parmat[s * Vn + t]; }\n\nEvalResult evaluate_route(const vector<int>& seq, bool detail = true) {\n    int L = (int)seq.size() - 1;\n    if (L <= 0) return {INF_SCORE, {}, {}};\n\n    vector<int> first(Vn, -1), last(Vn, -1), cnt(Vn, 0);\n    vector<long long> gapsum(Vn, 0);\n\n    for (int t = 1; t <= L; t++) {\n        int v = seq[t];\n        cnt[v]++;\n        if (first[v] == -1) {\n            first[v] = last[v] = t;\n        } else {\n            long long gap = t - last[v];\n            gapsum[v] += gap * (gap - 1) / 2;\n            last[v] = t;\n        }\n    }\n\n    long double total = 0;\n    vector<long long> contrib;\n    if (detail) contrib.assign(Vn, 0);\n\n    for (int v = 0; v < Vn; v++) {\n        if (cnt[v] == 0) return {INF_SCORE, {}, {}};\n        long long gap = first[v] + L - last[v];\n        gapsum[v] += gap * (gap - 1) / 2;\n        long long c = gapsum[v] * 1LL * dirt[v];\n        total += (long double)c;\n        if (detail) contrib[v] = c;\n    }\n\n    EvalResult res;\n    res.score = total / (long double)L;\n    if (detail) {\n        res.contrib = move(contrib);\n        res.cnt_in = move(cnt);\n    }\n    return res;\n}\n\nbool route_visits_all(const vector<int>& seq) {\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    for (int v : seq) seen[v] = 1;\n    for (int i = 0; i < Vn; i++) if (!seen[i]) return false;\n    return true;\n}\n\nvoid reconstruct_path_vertices(int s, int t, vector<int>& out) {\n    out.clear();\n    if (s == t) {\n        out.push_back(s);\n        return;\n    }\n    int cur = t;\n    out.push_back(t);\n    while (cur != s) {\n        cur = PAR(s, cur);\n        out.push_back(cur);\n    }\n    reverse(out.begin(), out.end());\n}\n\nbool append_path_mark(vector<int>& seq, int s, int t, vector<char>& seen, int& seen_cnt) {\n    if (s == t) return true;\n    static vector<int> path;\n    reconstruct_path_vertices(s, t, path);\n    for (int i = 1; i < (int)path.size(); i++) {\n        int v = path[i];\n        seq.push_back(v);\n        if (!seen[v]) {\n            seen[v] = 1;\n            seen_cnt++;\n        }\n        if ((int)seq.size() - 1 > 100000) return false;\n    }\n    return true;\n}\n\nbool build_route_from_waypoints(const vector<int>& wps, vector<int>& seq, vector<int>* used_wps_out = nullptr) {\n    seq.clear();\n    seq.push_back(0);\n\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n    vector<int> used_wps;\n    used_wps.reserve(wps.size());\n\n    for (int x : wps) {\n        if (seen[x]) continue;\n        if (!append_path_mark(seq, cur, x, seen, seen_cnt)) return false;\n        used_wps.push_back(x);\n        cur = x;\n    }\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        uint16_t bestd = numeric_limits<uint16_t>::max();\n        double bestpot = -1;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            uint16_t d = DIST(cur, v);\n            if (d < bestd || (d == bestd && potv[v] > bestpot)) {\n                bestd = d;\n                bestpot = potv[v];\n                best = v;\n            }\n        }\n        if (best == -1) break;\n        if (!append_path_mark(seq, cur, best, seen, seen_cnt)) return false;\n        used_wps.push_back(best);\n        cur = best;\n    }\n\n    if (!append_path_mark(seq, cur, 0, seen, seen_cnt)) return false;\n    if (!route_visits_all(seq)) return false;\n\n    if (used_wps_out) *used_wps_out = move(used_wps);\n    return true;\n}\n\nCandidate make_candidate_from_wps(const vector<int>& wps) {\n    Candidate c;\n    if (!build_route_from_waypoints(wps, c.seq, &c.wps)) {\n        c.score = INF_SCORE;\n        return c;\n    }\n    c.score = evaluate_route(c.seq, false).score;\n    return c;\n}\n\nint waypoint_chain_len(const vector<int>& wps) {\n    if (wps.empty()) return 0;\n    int len = DIST(0, wps[0]);\n    for (int i = 0; i + 1 < (int)wps.size(); i++) len += DIST(wps[i], wps[i + 1]);\n    len += DIST(wps.back(), 0);\n    return len;\n}\n\nvector<int> make_row_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; j++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int j = N - 1; j >= 0; j--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nvector<int> make_col_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int j = 0; j < N; j++) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; i++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int i = N - 1; i >= 0; i--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nuint64_t morton_code(int x, int y) {\n    uint64_t z = 0;\n    for (int b = 0; b < 6; b++) {\n        z |= ((uint64_t)((x >> b) & 1)) << (2 * b);\n        z |= ((uint64_t)((y >> b) & 1)) << (2 * b + 1);\n    }\n    return z;\n}\n\nvector<int> make_morton() {\n    vector<pair<uint64_t,int>> arr;\n    arr.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int v = VID(i, j);\n        if (v != 0) arr.push_back({morton_code(i, j), v});\n    }\n    sort(arr.begin(), arr.end());\n    vector<int> ord;\n    ord.reserve(arr.size());\n    for (auto &p : arr) ord.push_back(p.second);\n    return ord;\n}\n\nvector<int> make_pot_desc() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int v = 1; v < Vn; v++) ord.push_back(v);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (potv[a] != potv[b]) return potv[a] > potv[b];\n        return dirt[a] > dirt[b];\n    });\n    return ord;\n}\n\nvector<int> make_bfs_order() {\n    vector<int> ord;\n    vector<char> vis(Vn, 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        if (v != 0) ord.push_back(v);\n        for (int to : g[v]) if (!vis[to]) {\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_dfs_order() {\n    vector<int> ord;\n    vector<char> vis(Vn, 0);\n    vector<int> st = {0};\n    while (!st.empty()) {\n        int v = st.back();\n        st.pop_back();\n        if (vis[v]) continue;\n        vis[v] = 1;\n        if (v != 0) ord.push_back(v);\n        for (int i = (int)g[v].size() - 1; i >= 0; i--) {\n            int to = g[v][i];\n            if (!vis[to]) st.push_back(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_greedy_waypoints(double alpha, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double d = (double)DIST(cur, v);\n            double sc = potv[v] / pow(d + 1.0, alpha) + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nvector<int> make_greedy_mix(double lam, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double sc = potv[v] - lam * (double)DIST(cur, v) + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nvector<int> make_density_waypoints(double beta_return, double gamma_end, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double unc = 0.0;\n            int x = v;\n            while (x != cur) {\n                if (!seen[x]) unc += potv[x];\n                x = PAR(cur, x);\n            }\n            double len = DIST(cur, v);\n            double ret = DIST(v, 0);\n            double sc = unc / (len + beta_return * ret + 1.0)\n                      + gamma_end * potv[v] / (len + 1.0)\n                      + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nstring seq_to_moves(const vector<int>& seq) {\n    string ans;\n    ans.reserve(seq.size());\n    for (int i = 1; i < (int)seq.size(); i++) {\n        int a = seq[i - 1], b = seq[i];\n        int ar = a / N, ac = a % N;\n        int br = b / N, bc = b % N;\n        if (br == ar - 1 && bc == ac) ans.push_back('U');\n        else if (br == ar + 1 && bc == ac) ans.push_back('D');\n        else if (br == ar && bc == ac - 1) ans.push_back('L');\n        else if (br == ar && bc == ac + 1) ans.push_back('R');\n        else ans.push_back('?');\n    }\n    return ans;\n}\n\nvector<int> build_segment_anchor_to_x(int anchor, int x) {\n    vector<int> path;\n    reconstruct_path_vertices(anchor, x, path);\n    vector<int> seg;\n    for (int i = 1; i < (int)path.size(); i++) seg.push_back(path[i]);\n    for (int i = (int)path.size() - 2; i >= 0; i--) seg.push_back(path[i]);\n    return seg;\n}\n\nvector<int> build_segment_anchor_x_y(int anchor, int x, int y) {\n    vector<int> p1, p2, p3;\n    reconstruct_path_vertices(anchor, x, p1);\n    reconstruct_path_vertices(x, y, p2);\n    reconstruct_path_vertices(y, anchor, p3);\n\n    vector<int> seg;\n    for (int i = 1; i < (int)p1.size(); i++) seg.push_back(p1[i]);\n    for (int i = 1; i < (int)p2.size(); i++) seg.push_back(p2[i]);\n    for (int i = 1; i < (int)p3.size(); i++) seg.push_back(p3[i]);\n    return seg;\n}\n\nvector<int> apply_segment_periodic(\n    const vector<int>& seq,\n    int anchor,\n    const vector<int>& seg,\n    int step,\n    int offset\n) {\n    int L = (int)seq.size() - 1;\n    vector<int> res;\n    res.reserve(min(100000, L + 1 + 20000));\n    res.push_back(seq[0]);\n\n    int occ = 0;\n    bool inserted = false;\n\n    for (int i = 0; i < L; i++) {\n        int cur = seq[i];\n        if (cur == anchor) {\n            if (occ % step == offset) {\n                for (int x : seg) {\n                    res.push_back(x);\n                    if ((int)res.size() - 1 > 100000) return {};\n                }\n                inserted = true;\n            }\n            occ++;\n        }\n        res.push_back(seq[i + 1]);\n        if ((int)res.size() - 1 > 100000) return {};\n    }\n\n    if (!inserted) return {};\n    return res;\n}\n\nvoid improve_by_guided_delete(Candidate& cur, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n    while (timer.elapsed() < end_time && !cur.wps.empty()) {\n        int m = (int)cur.wps.size();\n        vector<pair<int,int>> deltas;\n        deltas.reserve(m);\n\n        for (int i = 0; i < m; i++) {\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            int c = (i + 1 == m ? 0 : cur.wps[i + 1]);\n            int delta = (int)DIST(a, c) - (int)DIST(a, b) - (int)DIST(b, c);\n            deltas.push_back({delta, i});\n        }\n        sort(deltas.begin(), deltas.end());\n        int K = min(10, (int)deltas.size());\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (int k = 0; k < K && timer.elapsed() < end_time; k++) {\n            int i = deltas[k].second;\n            if (i >= (int)cur.wps.size()) continue;\n            vector<int> nwps = cur.wps;\n            nwps.erase(nwps.begin() + i);\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + EPS < best_sc) {\n                best_sc = cand.score;\n                best_cand = move(cand);\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_hot_insert(Candidate& cur, const vector<int>& hot_vertices, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time) {\n        int m = (int)cur.wps.size();\n        vector<char> in_wps(Vn, 0);\n        for (int x : cur.wps) in_wps[x] = 1;\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        int HOT = min((int)hot_vertices.size(), 18);\n\n        for (int hi = 0; hi < HOT && timer.elapsed() < end_time; hi++) {\n            int x = hot_vertices[hi];\n            if (in_wps[x]) continue;\n\n            vector<pair<int,int>> pos_delta;\n            pos_delta.reserve(m + 1);\n\n            for (int pos = 0; pos <= m; pos++) {\n                int prev = (pos == 0 ? 0 : cur.wps[pos - 1]);\n                int next = (pos == m ? 0 : cur.wps[pos]);\n                int delta = (int)DIST(prev, x) + (int)DIST(x, next) - (int)DIST(prev, next);\n                pos_delta.push_back({delta, pos});\n            }\n\n            sort(pos_delta.begin(), pos_delta.end());\n            int K = min(4, (int)pos_delta.size());\n\n            for (int kk = 0; kk < K && timer.elapsed() < end_time; kk++) {\n                int pos = pos_delta[kk].second;\n                vector<int> nwps = cur.wps;\n                nwps.insert(nwps.begin() + pos, x);\n                Candidate cand = make_candidate_from_wps(nwps);\n                if (cand.score + EPS < best_sc) {\n                    best_sc = cand.score;\n                    best_cand = move(cand);\n                    found = true;\n                }\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_exact_hot_replace(Candidate& cur, const vector<int>& hot_vertices, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time && !cur.wps.empty()) {\n        int m = (int)cur.wps.size();\n        vector<char> in_wps(Vn, 0);\n        for (int x : cur.wps) in_wps[x] = 1;\n\n        vector<int> weak_pos(m);\n        iota(weak_pos.begin(), weak_pos.end(), 0);\n        sort(weak_pos.begin(), weak_pos.end(), [&](int i, int j) {\n            if (potv[cur.wps[i]] != potv[cur.wps[j]]) return potv[cur.wps[i]] < potv[cur.wps[j]];\n            return dirt[cur.wps[i]] < dirt[cur.wps[j]];\n        });\n        if ((int)weak_pos.size() > 10) weak_pos.resize(10);\n\n        vector<int> hot_free;\n        for (int x : hot_vertices) {\n            if (!in_wps[x]) hot_free.push_back(x);\n            if ((int)hot_free.size() >= 18) break;\n        }\n        if (hot_free.empty()) break;\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (int x : hot_free) {\n            if (timer.elapsed() >= end_time) break;\n\n            vector<pair<int,int>> ranked; // delta, pos\n            for (int pos : weak_pos) {\n                int oldv = cur.wps[pos];\n                int prev = (pos == 0 ? 0 : cur.wps[pos - 1]);\n                int next = (pos + 1 == m ? 0 : cur.wps[pos + 1]);\n                int oldc = (int)DIST(prev, oldv) + (int)DIST(oldv, next);\n                int newc = (int)DIST(prev, x) + (int)DIST(x, next);\n                ranked.push_back({newc - oldc, pos});\n            }\n            sort(ranked.begin(), ranked.end());\n            int K = min(4, (int)ranked.size());\n\n            for (int k = 0; k < K && timer.elapsed() < end_time; k++) {\n                int pos = ranked[k].second;\n                vector<int> nwps = cur.wps;\n                nwps[pos] = x;\n                Candidate cand = make_candidate_from_wps(nwps);\n                if (cand.score + EPS < best_sc) {\n                    best_sc = cand.score;\n                    best_cand = move(cand);\n                    found = true;\n                }\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_exact_two_opt_local(Candidate& cur, Timer& timer, double end_time, RNG& rng) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time) {\n        int m = (int)cur.wps.size();\n        if (m < 2) break;\n\n        vector<tuple<int,int,int>> cand_moves; // delta, i, j\n\n        // short local reversals\n        for (int i = 0; i < m; i++) {\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            for (int len = 1; len <= 10 && i + len < m; len++) {\n                int j = i + len;\n                int c = cur.wps[j];\n                int d = (j + 1 == m ? 0 : cur.wps[j + 1]);\n                int delta = (int)DIST(a, c) + (int)DIST(b, d)\n                          - (int)DIST(a, b) - (int)DIST(c, d);\n                cand_moves.push_back({delta, i, j});\n            }\n        }\n\n        // a few random long reversals\n        for (int t = 0; t < 100; t++) {\n            int i = rng.next_int(m);\n            int j = rng.next_int(m);\n            if (i > j) swap(i, j);\n            if (i == j) continue;\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            int c = cur.wps[j];\n            int d = (j + 1 == m ? 0 : cur.wps[j + 1]);\n            int delta = (int)DIST(a, c) + (int)DIST(b, d)\n                      - (int)DIST(a, b) - (int)DIST(c, d);\n            cand_moves.push_back({delta, i, j});\n        }\n\n        sort(cand_moves.begin(), cand_moves.end());\n        if ((int)cand_moves.size() > 12) cand_moves.resize(12);\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (auto [delta, i, j] : cand_moves) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> nwps = cur.wps;\n            reverse(nwps.begin() + i, nwps.begin() + j + 1);\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + EPS < best_sc) {\n                best_sc = cand.score;\n                best_cand = move(cand);\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    Vn = N * N;\n\n    vector<string> h(N - 1), vstr(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vstr[i];\n\n    dirt.assign(Vn, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        cin >> dirt[VID(i, j)];\n    }\n\n    g.assign(Vn, {});\n    for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) {\n        if (h[i][j] == '0') {\n            int a = VID(i, j), b = VID(i + 1, j);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n    for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) {\n        if (vstr[i][j] == '0') {\n            int a = VID(i, j), b = VID(i, j + 1);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n\n    // local potential\n    potv.assign(Vn, 0.0);\n    for (int s = 0; s < Vn; s++) {\n        potv[s] += dirt[s];\n        vector<int> dist(Vn, -1);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int x = q.front(); q.pop();\n            if (dist[x] == 3) continue;\n            for (int to : g[x]) {\n                if (dist[to] != -1) continue;\n                dist[to] = dist[x] + 1;\n                q.push(to);\n                if (dist[to] == 1) potv[s] += 0.50 * dirt[to];\n                else if (dist[to] == 2) potv[s] += 0.20 * dirt[to];\n                else if (dist[to] == 3) potv[s] += 0.08 * dirt[to];\n            }\n        }\n    }\n\n    for (int v = 0; v < Vn; v++) {\n        sort(g[v].begin(), g[v].end(), [&](int a, int b) {\n            if (potv[a] != potv[b]) return potv[a] > potv[b];\n            return dirt[a] > dirt[b];\n        });\n    }\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    // APSP + choose high-potential representative among shortest paths\n    distmat.assign((size_t)Vn * Vn, 0);\n    parmat.assign((size_t)Vn * Vn, 0);\n\n    vector<int> q(Vn);\n    vector<double> bestval(Vn);\n\n    for (int s = 0; s < Vn; s++) {\n        vector<int> order;\n        order.reserve(Vn);\n\n        for (int i = 0; i < Vn; i++) DIST(s, i) = numeric_limits<uint16_t>::max();\n\n        int qh = 0, qt = 0;\n        q[qt++] = s;\n        DIST(s, s) = 0;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            order.push_back(v);\n            uint16_t dv = DIST(s, v);\n            for (int to : g[v]) {\n                if (DIST(s, to) == numeric_limits<uint16_t>::max()) {\n                    DIST(s, to) = dv + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        for (int i = 0; i < Vn; i++) {\n            bestval[i] = -1e100;\n            PAR(s, i) = (uint16_t)i;\n        }\n        bestval[s] = potv[s];\n        PAR(s, s) = (uint16_t)s;\n\n        for (int v : order) {\n            for (int to : g[v]) {\n                if (DIST(s, to) == DIST(s, v) + 1) {\n                    double nv = bestval[v] + potv[to];\n                    if (nv > bestval[to] + 1e-12) {\n                        bestval[to] = nv;\n                        PAR(s, to) = (uint16_t)v;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Candidate> cands;\n    auto add_candidate = [&](const vector<int>& wps) {\n        Candidate c = make_candidate_from_wps(wps);\n        if (c.score < INF_SCORE) cands.push_back(move(c));\n    };\n\n    add_candidate(make_row_snake());\n    add_candidate(make_col_snake());\n    add_candidate(make_morton());\n    add_candidate(make_pot_desc());\n    add_candidate(make_bfs_order());\n    add_candidate(make_dfs_order());\n\n    add_candidate(make_greedy_waypoints(0.9, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.2, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.6, 0.0, rng));\n    add_candidate(make_greedy_waypoints(1.2, 30.0, rng));\n    add_candidate(make_greedy_mix(8.0, 20.0, rng));\n    add_candidate(make_greedy_mix(14.0, 30.0, rng));\n\n    add_candidate(make_density_waypoints(0.0, 0.05, 0.0, rng));\n    add_candidate(make_density_waypoints(0.2, 0.05, 0.0, rng));\n    add_candidate(make_density_waypoints(0.5, 0.08, 10.0, rng));\n\n    while (timer.elapsed() < 0.48) {\n        int t = rng.next_int(3);\n        if (t == 0) {\n            double alpha = 0.8 + 1.4 * rng.next_double();\n            double noise = 10.0 + 60.0 * rng.next_double();\n            add_candidate(make_greedy_waypoints(alpha, noise, rng));\n        } else if (t == 1) {\n            double lam = 6.0 + 16.0 * rng.next_double();\n            double noise = 10.0 + 50.0 * rng.next_double();\n            add_candidate(make_greedy_mix(lam, noise, rng));\n        } else {\n            double beta = 0.0 + 0.9 * rng.next_double();\n            double gamma = 0.02 + 0.10 * rng.next_double();\n            double noise = 0.0 + 20.0 * rng.next_double();\n            add_candidate(make_density_waypoints(beta, gamma, noise, rng));\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n        if (a.score != b.score) return a.score < b.score;\n        return waypoint_chain_len(a.wps) < waypoint_chain_len(b.wps);\n    });\n    if (cands.empty()) {\n        auto c = make_candidate_from_wps(make_row_snake());\n        cout << seq_to_moves(c.seq) << '\\n';\n        return 0;\n    }\n    if ((int)cands.size() > 6) cands.resize(6);\n\n    vector<int> hot_vertices;\n    for (int v = 1; v < Vn; v++) hot_vertices.push_back(v);\n    sort(hot_vertices.begin(), hot_vertices.end(), [&](int a, int b) {\n        if (potv[a] != potv[b]) return potv[a] > potv[b];\n        return dirt[a] > dirt[b];\n    });\n    if ((int)hot_vertices.size() > 120) hot_vertices.resize(120);\n\n    Candidate best = cands[0];\n\n    // main refinement on best candidate\n    {\n        Candidate cur = best;\n\n        improve_by_guided_delete(cur, timer, 0.95);\n        improve_by_hot_insert(cur, hot_vertices, timer, 1.12);\n        improve_by_exact_hot_replace(cur, hot_vertices, timer, 1.28);\n        improve_by_exact_two_opt_local(cur, timer, 1.42, rng);\n\n        while (timer.elapsed() < 1.64 && !cur.wps.empty()) {\n            vector<int> nwps = cur.wps;\n            int m = (int)nwps.size();\n            int op = rng.next_int(6);\n\n            if (op == 0 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i > j) swap(i, j);\n                if (i == j) continue;\n                reverse(nwps.begin() + i, nwps.begin() + j + 1);\n            } else if (op == 1 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i == j) continue;\n                swap(nwps[i], nwps[j]);\n            } else if (op == 2 && m >= 1) {\n                int i = rng.next_int(m);\n                nwps.erase(nwps.begin() + i);\n            } else if (op == 3 && m >= 1) {\n                int pos = rng.next_int(m + 1);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool ex = false;\n                for (int y : nwps) if (y == x) { ex = true; break; }\n                if (ex) continue;\n                nwps.insert(nwps.begin() + pos, x);\n            } else if (op == 4 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i == j) continue;\n                int v = nwps[i];\n                nwps.erase(nwps.begin() + i);\n                if (j > i) j--;\n                nwps.insert(nwps.begin() + j, v);\n            } else if (op == 5 && m >= 1) {\n                int i = rng.next_int(m);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool ex = false;\n                for (int y : nwps) if (y == x) { ex = true; break; }\n                if (ex) continue;\n                nwps[i] = x;\n            } else {\n                continue;\n            }\n\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + 1e-12L < cur.score) cur = move(cand);\n        }\n\n        improve_by_guided_delete(cur, timer, 1.74);\n        improve_by_exact_hot_replace(cur, hot_vertices, timer, 1.82);\n\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    // light refinement on other good candidates\n    for (int idx = 1; idx < (int)cands.size() && timer.elapsed() < 1.84; idx++) {\n        Candidate cur = cands[idx];\n        improve_by_guided_delete(cur, timer, 1.88);\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    // route-level periodic excursions\n    vector<int> cur_seq = best.seq;\n    EvalResult cur_ev = evaluate_route(cur_seq, true);\n\n    const vector<pair<int,int>> patterns = {\n        {1,0},\n        {2,0},{2,1},\n        {3,0},{3,1},{3,2},\n        {4,0},{4,1},{4,2},{4,3},\n        {5,0},{5,1},{5,2},{5,3},{5,4}\n    };\n\n    for (int round = 0; round < 10 && timer.elapsed() < 1.93; round++) {\n        int L = (int)cur_seq.size() - 1;\n        if (L > 98000) break;\n\n        vector<int> rankv(Vn);\n        iota(rankv.begin(), rankv.end(), 0);\n        sort(rankv.begin(), rankv.end(), [&](int a, int b) {\n            return cur_ev.contrib[a] > cur_ev.contrib[b];\n        });\n\n        vector<int> occ_pos_cnt(Vn, 0);\n        for (int i = 0; i < L; i++) occ_pos_cnt[cur_seq[i]]++;\n\n        long double best_sc = cur_ev.score;\n        vector<int> best_seq2;\n\n        int TOPX = min(Vn, 16);\n        for (int ii = 0; ii < TOPX && timer.elapsed() < 1.92; ii++) {\n            int x = rankv[ii];\n\n            vector<pair<double,int>> anchors;\n            for (int a = 0; a < Vn; a++) {\n                if (a == x || occ_pos_cnt[a] == 0) continue;\n                int d = DIST(a, x);\n                if (d == 0) continue;\n                if (d > 12 && occ_pos_cnt[a] <= 1) continue;\n                double sc = (double)occ_pos_cnt[a] / (double)(d + 1) + 0.001 * potv[a];\n                anchors.push_back({-sc, a});\n            }\n            sort(anchors.begin(), anchors.end());\n            if ((int)anchors.size() > 6) anchors.resize(6);\n\n            // single-target excursion\n            for (auto &pa : anchors) {\n                int a = pa.second;\n                vector<int> seg = build_segment_anchor_to_x(a, x);\n                if (seg.empty()) continue;\n                for (auto [step, off] : patterns) {\n                    auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                    if (cand_seq.empty()) continue;\n                    auto ev = evaluate_route(cand_seq, false);\n                    if (ev.score + 1e-12L < best_sc) {\n                        best_sc = ev.score;\n                        best_seq2 = move(cand_seq);\n                    }\n                }\n            }\n\n            // nearby two-hotspot excursion\n            vector<int> ycand;\n            for (int jj = 0; jj < min(Vn, 40) && (int)ycand.size() < 4; jj++) {\n                int y = rankv[jj];\n                if (y == x) continue;\n                if (DIST(x, y) <= 6) ycand.push_back(y);\n            }\n\n            for (int y : ycand) {\n                for (auto &pa : anchors) {\n                    int a = pa.second;\n                    int cyc_len = DIST(a, x) + DIST(x, y) + DIST(y, a);\n                    if (cyc_len > 20) continue;\n                    vector<int> seg = build_segment_anchor_x_y(a, x, y);\n                    if (seg.empty()) continue;\n                    for (auto [step, off] : patterns) {\n                        auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                        if (cand_seq.empty()) continue;\n                        auto ev = evaluate_route(cand_seq, false);\n                        if (ev.score + 1e-12L < best_sc) {\n                            best_sc = ev.score;\n                            best_seq2 = move(cand_seq);\n                        }\n                    }\n                }\n            }\n        }\n\n        if (best_seq2.empty()) break;\n        cur_seq = move(best_seq2);\n        cur_ev = evaluate_route(cur_seq, true);\n    }\n\n    cout << seq_to_moves(cur_seq) << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int INF = 1e9;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    int N, M;\n    int si, sj;\n    vector<string> board;\n    vector<string> words;\n\n    vector<pair<int,int>> posByChar[26];\n\n    vector<vector<int>> ov;\n    vector<int> startApprox;\n    vector<vector<int>> edgeApprox;\n    vector<int> startLen;\n    vector<vector<int>> edgeLen;\n\n    int charStart[26];\n    int charTrans[26][26];\n\n    static constexpr int POW26_4 = 26 * 26 * 26 * 26;\n    static constexpr int POW26_5 = POW26_4 * 26;\n    vector<int16_t> id5;\n\n    Timer timer;\n    const double TL = 1.90;\n\n    inline int dist(const pair<int,int>& a, const pair<int,int>& b) const {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    int overlap5(const string& a, const string& b) {\n        for (int k = 4; k >= 0; --k) {\n            bool ok = true;\n            for (int t = 0; t < k; ++t) {\n                if (a[5 - k + t] != b[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    int encode5(const string& s) const {\n        int x = 0;\n        for (int i = 0; i < 5; ++i) x = x * 26 + (s[i] - 'A');\n        return x;\n    }\n\n    int cost_from_prev_char(int prevChar, const string& s) {\n        if (s.empty()) return 0;\n        const auto& initList = posByChar[prevChar];\n        vector<int> dp(initList.size(), 0), ndp;\n        const vector<pair<int,int>>* prevList = &initList;\n\n        for (char ch : s) {\n            int c = ch - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    int cost_from_start(const string& s) {\n        if (s.empty()) return 0;\n        int c0 = s[0] - 'A';\n        const auto& firstList = posByChar[c0];\n        vector<int> dp(firstList.size()), ndp;\n        for (int i = 0; i < (int)firstList.size(); ++i) {\n            dp[i] = abs(si - firstList[i].first) + abs(sj - firstList[i].second) + 1;\n        }\n        const vector<pair<int,int>>* prevList = &firstList;\n\n        for (int p = 1; p < (int)s.size(); ++p) {\n            int c = s[p] - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    void preprocess() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                posByChar[board[i][j] - 'A'].push_back({i, j});\n            }\n        }\n\n        for (int c = 0; c < 26; ++c) {\n            charStart[c] = INF;\n            for (auto &p : posByChar[c]) {\n                charStart[c] = min(charStart[c], abs(si - p.first) + abs(sj - p.second) + 1);\n            }\n        }\n        for (int a = 0; a < 26; ++a) {\n            for (int b = 0; b < 26; ++b) {\n                int best = INF;\n                for (auto &pa : posByChar[a]) for (auto &pb : posByChar[b]) {\n                    best = min(best, dist(pa, pb) + 1);\n                }\n                charTrans[a][b] = best;\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                ov[i][j] = overlap5(words[i], words[j]);\n            }\n        }\n\n        startApprox.assign(M, 0);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        startLen.assign(M, 5);\n        edgeLen.assign(M, vector<int>(M, 5));\n\n        for (int i = 0; i < M; ++i) {\n            startApprox[i] = cost_from_start(words[i]);\n        }\n\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                int r = ov[i][j];\n                string chunk = words[j].substr(r);\n                edgeApprox[i][j] = cost_from_prev_char(words[i][4] - 'A', chunk);\n                edgeLen[i][j] = 5 - r;\n            }\n        }\n\n        id5.assign(POW26_5, (int16_t)-1);\n        for (int i = 0; i < M; ++i) {\n            id5[encode5(words[i])] = (int16_t)i;\n        }\n    }\n\n    int insertion_delta(\n        const vector<int>& path,\n        int x, int pos,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int m = (int)path.size();\n        if (m == 0) return startC[x];\n        if (pos == 0) {\n            return startC[x] + edgeC[x][path[0]] - startC[path[0]];\n        } else if (pos == m) {\n            return edgeC[path[m - 1]][x];\n        } else {\n            return edgeC[path[pos - 1]][x] + edgeC[x][path[pos]] - edgeC[path[pos - 1]][path[pos]];\n        }\n    }\n\n    vector<int> build_order_cheapest_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        path.push_back(a);\n        used[a] = 1;\n        if (b != -1) {\n            path.push_back(b);\n            used[b] = 1;\n        }\n\n        while ((int)path.size() < M) {\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n        return path;\n    }\n\n    vector<int> build_order_randomized_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        mt19937& rng\n    ) {\n        struct Cand {\n            int delta, x, pos;\n        };\n\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        path.push_back(a);\n        used[a] = 1;\n        if (b != -1) {\n            path.push_back(b);\n            used[b] = 1;\n        }\n\n        while ((int)path.size() < M) {\n            Cand best[3];\n            for (int t = 0; t < 3; ++t) best[t] = {INF, -1, -1};\n\n            auto push_cand = [&](int delta, int x, int pos) {\n                Cand cur{delta, x, pos};\n                for (int t = 0; t < 3; ++t) {\n                    if (cur.delta < best[t].delta) {\n                        swap(cur, best[t]);\n                    }\n                }\n            };\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    push_cand(d, x, pos);\n                }\n            }\n\n            int cnt = 0;\n            while (cnt < 3 && best[cnt].x != -1) ++cnt;\n\n            int pick = 0;\n            if (cnt >= 2) {\n                uint32_t r = rng() % 100;\n                if (cnt == 2) {\n                    pick = (r < 75 ? 0 : 1);\n                } else {\n                    if (r < 70) pick = 0;\n                    else if (r < 92) pick = 1;\n                    else pick = 2;\n                }\n            }\n\n            path.insert(path.begin() + best[pick].pos, best[pick].x);\n            used[best[pick].x] = 1;\n        }\n\n        return path;\n    }\n\n    vector<int> improve_relocate(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int maxIter = 200\n    ) {\n        int n = (int)path.size();\n        for (int iter = 0; iter < maxIter; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (int i = 0; i < n; ++i) {\n                int x = path[i];\n\n                int remDelta;\n                if (i == 0) {\n                    int b = path[1];\n                    remDelta = startC[b] - startC[x] - edgeC[x][b];\n                } else if (i == n - 1) {\n                    int a = path[n - 2];\n                    remDelta = -edgeC[a][x];\n                } else {\n                    int a = path[i - 1];\n                    int b = path[i + 1];\n                    remDelta = edgeC[a][b] - edgeC[a][x] - edgeC[x][b];\n                }\n\n                for (int j = 0; j <= n - 1; ++j) {\n                    if (j == i) continue;\n\n                    int left = -1, right = -1;\n                    if (j < i) {\n                        left = (j == 0 ? -1 : path[j - 1]);\n                        right = path[j];\n                    } else {\n                        left = path[j];\n                        right = (j == n - 1 ? -1 : path[j + 1]);\n                    }\n\n                    int insDelta;\n                    if (left == -1) {\n                        insDelta = startC[x] + edgeC[x][right] - startC[right];\n                    } else if (right == -1) {\n                        insDelta = edgeC[left][x];\n                    } else {\n                        insDelta = edgeC[left][x] + edgeC[x][right] - edgeC[left][right];\n                    }\n\n                    int delta = remDelta + insDelta;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            int x = path[bestI];\n            path.erase(path.begin() + bestI);\n            path.insert(path.begin() + bestJ, x);\n\n            if (timer.elapsed() > TL) break;\n        }\n        return path;\n    }\n\n    string build_string(const vector<int>& order) {\n        string s = words[order[0]];\n        s.reserve(5 + 4 * M);\n        for (int k = 1; k < M; ++k) {\n            int i = order[k - 1];\n            int j = order[k];\n            int r = ov[i][j];\n            s += words[j].substr(r);\n        }\n        return s;\n    }\n\n    struct WindowCand {\n        int l, r, len, approx;\n        bool operator<(const WindowCand& other) const {\n            if (len != other.len) return len < other.len;\n            if (approx != other.approx) return approx < other.approx;\n            if (l != other.l) return l < other.l;\n            return r < other.r;\n        }\n    };\n\n    vector<WindowCand> covering_window_candidates(const string& s, int keepK = 2) {\n        int L = (int)s.size();\n        if (L < 5) return {{0, L - 1, L, 0}};\n\n        int T = L - 4;\n        vector<int> ids(T, -1);\n\n        int code = 0;\n        for (int i = 0; i < 5; ++i) code = code * 26 + (s[i] - 'A');\n        ids[0] = id5[code];\n        for (int p = 1; p < T; ++p) {\n            code = (code % POW26_4) * 26 + (s[p + 4] - 'A');\n            ids[p] = id5[code];\n        }\n\n        vector<int> pairPref(L, 0);\n        for (int i = 1; i < L; ++i) {\n            pairPref[i] = pairPref[i - 1] + charTrans[s[i - 1] - 'A'][s[i] - 'A'];\n        }\n\n        auto approxCostSub = [&](int l, int r) -> int {\n            int res = charStart[s[l] - 'A'];\n            res += pairPref[r] - pairPref[l];\n            return res;\n        };\n\n        vector<int> cnt(M, 0);\n        int covered = 0;\n        int l = 0;\n        vector<WindowCand> all;\n        int bestLen = INF;\n\n        for (int r = 0; r < T; ++r) {\n            int id = ids[r];\n            if (id != -1) {\n                if (cnt[id]++ == 0) ++covered;\n            }\n\n            while (covered == M) {\n                while (l <= r && (ids[l] == -1 || cnt[ids[l]] > 1)) {\n                    if (ids[l] != -1) --cnt[ids[l]];\n                    ++l;\n                }\n                int cl = l;\n                int cr = r + 4;\n                int len = cr - cl + 1;\n                bestLen = min(bestLen, len);\n                all.push_back({cl, cr, len, approxCostSub(cl, cr)});\n\n                if (ids[l] != -1) {\n                    if (--cnt[ids[l]] == 0) --covered;\n                }\n                ++l;\n            }\n        }\n\n        if (all.empty()) {\n            return {{0, L - 1, L, approxCostSub(0, L - 1)}};\n        }\n\n        vector<WindowCand> cand;\n        for (auto &w : all) {\n            if (w.len <= bestLen + 2) cand.push_back(w);\n        }\n        sort(cand.begin(), cand.end());\n\n        vector<WindowCand> res;\n        for (auto &w : cand) {\n            bool dup = false;\n            for (auto &u : res) {\n                if (u.l == w.l && u.r == w.r) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                res.push_back(w);\n                if ((int)res.size() >= keepK) break;\n            }\n        }\n\n        bool hasWhole = false;\n        for (auto &w : res) {\n            if (w.l == 0 && w.r == L - 1) hasWhole = true;\n        }\n        if (!hasWhole) {\n            res.push_back({0, L - 1, L, approxCostSub(0, L - 1)});\n        }\n        return res;\n    }\n\n    pair<int, vector<pair<int,int>>> exact_positions_for_string(const string& s) {\n        int L = (int)s.size();\n        vector<vector<int16_t>> parent(L);\n        vector<int> dp, ndp;\n        const vector<pair<int,int>>* prevList = nullptr;\n\n        for (int t = 0; t < L; ++t) {\n            int c = s[t] - 'A';\n            const auto& curList = posByChar[c];\n            parent[t].assign(curList.size(), -1);\n            ndp.assign(curList.size(), INF);\n\n            if (t == 0) {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    ndp[j] = abs(si - curList[j].first) + abs(sj - curList[j].second) + 1;\n                }\n            } else {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    int best = INF, bestPrev = -1;\n                    for (int i = 0; i < (int)prevList->size(); ++i) {\n                        int cand = dp[i] + dist((*prevList)[i], curList[j]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestPrev = i;\n                        }\n                    }\n                    ndp[j] = best;\n                    parent[t][j] = (int16_t)bestPrev;\n                }\n            }\n\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n\n        int lastIdx = (int)(min_element(dp.begin(), dp.end()) - dp.begin());\n        int bestCost = dp[lastIdx];\n\n        vector<pair<int,int>> ops(L);\n        int idx = lastIdx;\n        for (int t = L - 1; t >= 0; --t) {\n            int c = s[t] - 'A';\n            ops[t] = posByChar[c][idx];\n            idx = parent[t][idx];\n        }\n\n        return {bestCost, ops};\n    }\n\n    void evaluate_order(\n        const vector<int>& order,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub\n    ) {\n        string s = build_string(order);\n        auto wins = covering_window_candidates(s, 2);\n\n        for (auto &w : wins) {\n            string sub = s.substr(w.l, w.len);\n            size_t hs = hash<string>{}(sub);\n            if (!seenSub.insert(hs).second) continue;\n\n            auto [cost, ops] = exact_positions_for_string(sub);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestOps = move(ops);\n            }\n        }\n    }\n\n    void try_objective(\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int polishIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub\n    ) {\n        vector<tuple<int,int,int>> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                pairs.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(pairs.begin(), pairs.end());\n\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            auto [c, a, b] = pairs[idx];\n            (void)c;\n\n            auto order = build_order_cheapest_insertion(a, b, startC, edgeC);\n            order = improve_relocate(order, startC, edgeC, polishIter);\n            evaluate_order(order, bestCost, bestOps, seenSub);\n        }\n    }\n\n    void try_randomized_objective(\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int triesPerPair,\n        int polishIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        mt19937& rng\n    ) {\n        vector<tuple<int,int,int>> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                pairs.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(pairs.begin(), pairs.end());\n\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            auto [c, a, b] = pairs[idx];\n            (void)c;\n\n            for (int t = 0; t < triesPerPair; ++t) {\n                if (timer.elapsed() > TL) return;\n                auto order = build_order_randomized_insertion(a, b, startC, edgeC, rng);\n                order = improve_relocate(order, startC, edgeC, polishIter);\n                evaluate_order(order, bestCost, bestOps, seenSub);\n            }\n        }\n    }\n\n    void solve() {\n        preprocess();\n        timer.reset();\n\n        uint64_t seed = 88172645463325252ULL;\n        seed ^= (uint64_t)si * 1000003ULL + (uint64_t)sj * 10007ULL;\n        for (auto &w : words) for (char c : w) seed = seed * 1315423911ULL + (unsigned)c;\n        mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n        int bestCost = INF;\n        vector<pair<int,int>> bestOps;\n        unordered_set<size_t> seenSub;\n        seenSub.reserve(256);\n\n        if (M == 1) {\n            auto [cost, ops] = exact_positions_for_string(words[0]);\n            (void)cost;\n            bestOps = move(ops);\n        } else {\n            // Strong deterministic baseline\n            try_objective(startApprox, edgeApprox, 20, 200, bestCost, bestOps, seenSub);\n\n            if (timer.elapsed() <= TL) {\n                try_objective(startLen, edgeLen, 12, 160, bestCost, bestOps, seenSub);\n            }\n\n            if (timer.elapsed() <= TL) {\n                vector<tuple<int,int,int>> pairs;\n                for (int a = 0; a < M; ++a) {\n                    for (int b = 0; b < M; ++b) if (a != b) {\n                        pairs.emplace_back(startLen[a] + edgeLen[a][b], a, b);\n                    }\n                }\n                sort(pairs.begin(), pairs.end());\n                int use = min(12, (int)pairs.size());\n                for (int idx = 0; idx < use; ++idx) {\n                    if (timer.elapsed() > TL) break;\n                    auto [c, a, b] = pairs[idx];\n                    (void)c;\n\n                    auto order = build_order_cheapest_insertion(a, b, startLen, edgeLen);\n                    order = improve_relocate(order, startLen, edgeLen, 120);\n                    order = improve_relocate(order, startApprox, edgeApprox, 80);\n                    evaluate_order(order, bestCost, bestOps, seenSub);\n                }\n            }\n\n            // Cheap diversification around strongest seeds\n            if (timer.elapsed() <= 1.35) {\n                try_randomized_objective(startApprox, edgeApprox, 4, 2, 90, bestCost, bestOps, seenSub, rng);\n            }\n            if (timer.elapsed() <= 1.55) {\n                try_randomized_objective(startLen, edgeLen, 3, 1, 80, bestCost, bestOps, seenSub, rng);\n            }\n        }\n\n        if (bestOps.empty()) {\n            string s;\n            for (auto& w : words) s += w;\n            auto [cost, ops] = exact_positions_for_string(s);\n            (void)cost;\n            bestOps = move(ops);\n        }\n\n        for (auto [i, j] : bestOps) {\n            cout << i << ' ' << j << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M;\n    cin >> solver.si >> solver.sj;\n    solver.board.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.board[i];\n    solver.words.resize(solver.M);\n    for (int i = 0; i < solver.M; ++i) cin >> solver.words[i];\n\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 20;\nstatic constexpr int MAXC = 400;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n} rng;\n\nstruct Placement {\n    vector<uint16_t> cells;\n    bitset<MAXC> mask;\n    vector<uint8_t> contrib;\n    vector<uint16_t> drill_ids;\n    bool valid = true;\n};\n\nstruct Field {\n    vector<pair<int,int>> shape;\n    vector<Placement> ps;\n    int valid_count = 0;\n};\n\nstruct SavedState {\n    array<short, MAXM> choice{};\n    int exact_err = INT_MAX;\n    double noisy = 1e100;\n};\n\nstruct SearchState {\n    array<short, MAXM> choice{};\n    vector<int> feat;\n    vector<int> pred;\n    int exact_err = 0;\n    double noisy = 0.0;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n\n    vector<Field> fields;\n\n    int rb[5], cb[5];\n    int block_id[MAXN][MAXN];\n\n    int Q = 0;\n    vector<vector<int>> query_cells;\n    vector<bitset<MAXC>> query_masks;\n    vector<double> estQ, wQ;\n    vector<int> qSize;\n\n    vector<vector<pair<uint8_t, uint16_t>>> coverList;\n\n    vector<int> drill_cells;\n    vector<int> drill_obs;\n    vector<int> cell_to_drill;\n    vector<int> exact_v;\n\n    vector<int> mark, chg, aff;\n    int iter_mark = 1;\n\n    chrono::steady_clock::time_point st;\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool better_pair(int e1, double n1, int e2, double n2) const {\n        if (e1 != e2) return e1 < e2;\n        return n1 + 1e-12 < n2;\n    }\n\n    int ask_divination(const vector<int>& cells) {\n        cout << \"q \" << cells.size();\n        for (int id : cells) cout << ' ' << id / N << ' ' << id % N;\n        cout << endl;\n        cout.flush();\n        int y;\n        cin >> y;\n        return y;\n    }\n\n    int ask_drill(int cell) {\n        cout << \"q 1 \" << cell / N << ' ' << cell % N << endl;\n        cout.flush();\n        int v;\n        cin >> v;\n        return v;\n    }\n\n    bool ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int id : cells) cout << ' ' << id / N << ' ' << id % N;\n        cout << endl;\n        cout.flush();\n        int ok;\n        cin >> ok;\n        return ok == 1;\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        alpha = 1.0 - 2.0 * eps;\n        C = N * N;\n\n        fields.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int d;\n            cin >> d;\n            fields[k].shape.resize(d);\n            for (int t = 0; t < d; ++t) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].shape[t] = {i, j};\n            }\n        }\n\n        coverList.assign(C, {});\n        cell_to_drill.assign(C, -1);\n        exact_v.assign(C, -1);\n    }\n\n    void build_blocks() {\n        for (int t = 0; t <= 4; ++t) {\n            rb[t] = (long long)t * N / 4;\n            cb[t] = (long long)t * N / 4;\n        }\n        for (int i = 0; i < N; ++i) {\n            int bi = 0;\n            while (!(rb[bi] <= i && i < rb[bi + 1])) ++bi;\n            for (int j = 0; j < N; ++j) {\n                int bj = 0;\n                while (!(cb[bj] <= j && j < cb[bj + 1])) ++bj;\n                block_id[i][j] = bi * 4 + bj;\n            }\n        }\n    }\n\n    void add_query_set(const vector<int>& cells) {\n        if ((int)cells.size() < 2) return;\n        bitset<MAXC> bs;\n        for (int id : cells) bs.set(id);\n        query_cells.push_back(cells);\n        query_masks.push_back(bs);\n    }\n\n    void build_query_sets() {\n        query_cells.clear();\n        query_masks.clear();\n\n        int mode = 0;\n        if (M <= 5 && eps <= 0.15) mode = 3;\n        else if (M <= 8 && eps <= 0.12) mode = 2;\n        else if ((M <= 12 && eps <= 0.10) || (M <= 15 && eps <= 0.05)) mode = 1;\n        else mode = 0;\n\n        if (mode >= 2) {\n            for (int i = 0; i < N; ++i) {\n                vector<int> cells;\n                for (int j = 0; j < N; ++j) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n            for (int j = 0; j < N; ++j) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n        }\n\n        if (mode >= 1) {\n            for (int bi = 0; bi < 4; ++bi) {\n                for (int bj = 0; bj < 4; ++bj) {\n                    vector<int> cells;\n                    for (int i = rb[bi]; i < rb[bi + 1]; ++i) {\n                        for (int j = cb[bj]; j < cb[bj + 1]; ++j) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    add_query_set(cells);\n                }\n            }\n        } else {\n            for (int bi = 0; bi < 2; ++bi) {\n                for (int bj = 0; bj < 2; ++bj) {\n                    int r0 = (long long)bi * N / 2;\n                    int r1 = (long long)(bi + 1) * N / 2;\n                    int c0 = (long long)bj * N / 2;\n                    int c1 = (long long)(bj + 1) * N / 2;\n                    vector<int> cells;\n                    for (int i = r0; i < r1; ++i) {\n                        for (int j = c0; j < c1; ++j) cells.push_back(i * N + j);\n                    }\n                    add_query_set(cells);\n                }\n            }\n        }\n\n        if (mode == 3) {\n            for (int t = 0; t < 4; ++t) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        int f = 0;\n                        if (t == 0) f = ((i + j) & 1);\n                        if (t == 1) f = (i & 1);\n                        if (t == 2) f = (j & 1);\n                        if (t == 3) f = (((i / 2) + (j / 2)) & 1);\n                        if (f) cells.push_back(i * N + j);\n                    }\n                }\n                if ((int)cells.size() >= 2 && (int)cells.size() < C) add_query_set(cells);\n            }\n        }\n\n        // Harder cases: add only a couple of very cheap global patterns.\n        if (mode <= 1) {\n            for (int t = 0; t < 2; ++t) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        int f = 0;\n                        if (t == 0) f = ((i + j) & 1);\n                        if (t == 1) f = (((i / 2) + (j / 2)) & 1);\n                        if (f) cells.push_back(i * N + j);\n                    }\n                }\n                if ((int)cells.size() >= 2 && (int)cells.size() < C) add_query_set(cells);\n            }\n        }\n\n        Q = (int)query_cells.size();\n        estQ.assign(Q, 0.0);\n        wQ.assign(Q, 0.0);\n        qSize.assign(Q, 0);\n    }\n\n    void ask_initial_queries() {\n        for (int q = 0; q < Q; ++q) {\n            int y = ask_divination(query_cells[q]);\n            int k = (int)query_cells[q].size();\n            qSize[q] = k;\n            estQ[q] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[q] = 1.0 / var_est;\n        }\n    }\n\n    void enumerate_placements() {\n        for (int k = 0; k < M; ++k) {\n            int max_i = 0, max_j = 0;\n            for (auto [i, j] : fields[k].shape) {\n                max_i = max(max_i, i);\n                max_j = max(max_j, j);\n            }\n\n            for (int di = 0; di + max_i < N; ++di) {\n                for (int dj = 0; dj + max_j < N; ++dj) {\n                    Placement p;\n                    p.contrib.assign(Q, 0);\n\n                    for (auto [si, sj] : fields[k].shape) {\n                        int i = di + si;\n                        int j = dj + sj;\n                        int id = i * N + j;\n                        p.cells.push_back((uint16_t)id);\n                        p.mask.set(id);\n                    }\n\n                    for (int q = 0; q < Q; ++q) {\n                        uint8_t c = 0;\n                        for (int id : p.cells) c += (uint8_t)query_masks[q].test(id);\n                        p.contrib[q] = c;\n                    }\n\n                    int idx = (int)fields[k].ps.size();\n                    for (int id : p.cells) coverList[id].push_back({(uint8_t)k, (uint16_t)idx});\n                    fields[k].ps.push_back(std::move(p));\n                }\n            }\n            fields[k].valid_count = (int)fields[k].ps.size();\n        }\n    }\n\n    bool usable_placement(int k, int p) const {\n        return fields[k].ps[p].valid;\n    }\n\n    bool invalidate_field_by_cover_state(int k, int cell, bool must_cover) {\n        bool changed = false;\n        for (auto &pl : fields[k].ps) {\n            if (!pl.valid) continue;\n            bool cov = pl.mask.test(cell);\n            if (cov != must_cover) {\n                pl.valid = false;\n                fields[k].valid_count--;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void register_drill(int cell, int v) {\n        exact_v[cell] = v;\n        if (cell_to_drill[cell] == -1) {\n            int idx = (int)drill_cells.size();\n            cell_to_drill[cell] = idx;\n            drill_cells.push_back(cell);\n            drill_obs.push_back(v);\n\n            mark.resize(drill_cells.size(), 0);\n            chg.resize(drill_cells.size(), 0);\n\n            for (auto [fk, pi] : coverList[cell]) {\n                fields[fk].ps[pi].drill_ids.push_back((uint16_t)idx);\n            }\n        } else {\n            drill_obs[cell_to_drill[cell]] = v;\n        }\n\n        if (v == 0) {\n            for (auto [fk, pi] : coverList[cell]) {\n                auto &pl = fields[fk].ps[pi];\n                if (pl.valid) {\n                    pl.valid = false;\n                    fields[fk].valid_count--;\n                }\n            }\n        }\n    }\n\n    void propagate_constraints() {\n        if (drill_cells.empty()) return;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int did = 0; did < (int)drill_cells.size(); ++did) {\n                int cell = drill_cells[did];\n                int req = drill_obs[did];\n\n                int sure = 0, poss = 0;\n                vector<uint8_t> state(M, 0);\n\n                for (int k = 0; k < M; ++k) {\n                    bool any0 = false, any1 = false;\n                    for (const auto &pl : fields[k].ps) {\n                        if (!pl.valid) continue;\n                        bool cov = pl.mask.test(cell);\n                        if (cov) any1 = true;\n                        else any0 = true;\n                        if (any0 && any1) break;\n                    }\n                    if (!any0 && !any1) return;\n\n                    if (any1 && !any0) {\n                        state[k] = 1;\n                        sure++;\n                        poss++;\n                    } else if (any1 && any0) {\n                        state[k] = 2;\n                        poss++;\n                    } else {\n                        state[k] = 3;\n                    }\n                }\n\n                if (sure > req || poss < req) return;\n\n                if (sure == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) changed |= invalidate_field_by_cover_state(k, cell, false);\n                    }\n                }\n                if (poss == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) changed |= invalidate_field_by_cover_state(k, cell, true);\n                    }\n                }\n            }\n        }\n    }\n\n    bool all_fields_unique(vector<int>& ans_cells) const {\n        bitset<MAXC> uni;\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count != 1) return false;\n            for (const auto &pl : fields[k].ps) {\n                if (pl.valid) {\n                    uni |= pl.mask;\n                    break;\n                }\n            }\n        }\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (uni.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    bitset<MAXC> compute_possible_union() const {\n        bitset<MAXC> uni;\n        for (int k = 0; k < M; ++k) {\n            for (const auto &pl : fields[k].ps) if (pl.valid) uni |= pl.mask;\n        }\n        return uni;\n    }\n\n    vector<int> possible_union_unknown_cells() const {\n        auto uni = compute_possible_union();\n        vector<int> res;\n        for (int id = 0; id < C; ++id) {\n            if (uni.test(id) && exact_v[id] == -1) res.push_back(id);\n        }\n        return res;\n    }\n\n    double initial_noisy0() const {\n        double s = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            double r = -estQ[q];\n            s += wQ[q] * r * r;\n        }\n        return s;\n    }\n\n    void calc_delta_parts(const SearchState& s, int field_idx, int newp, int &dExact, double &dNoisy) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) {\n            dExact = 0;\n            dNoisy = 0.0;\n            return;\n        }\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        dNoisy = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            dNoisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n        }\n\n        dExact = 0;\n        if (drill_cells.empty()) return;\n\n        ++iter_mark;\n        if (iter_mark == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            iter_mark = 1;\n        }\n        aff.clear();\n\n        if (oldpl) {\n            for (int id : oldpl->drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]--;\n            }\n        }\n        for (int id : newpl.drill_ids) {\n            if (mark[id] != iter_mark) {\n                mark[id] = iter_mark;\n                chg[id] = 0;\n                aff.push_back(id);\n            }\n            chg[id]++;\n        }\n\n        for (int id : aff) {\n            int oc = s.pred[id];\n            int nc = oc + chg[id];\n            int obs = drill_obs[id];\n            dExact += (nc - obs) * (nc - obs) - (oc - obs) * (oc - obs);\n        }\n    }\n\n    void apply_change(SearchState& s, int field_idx, int newp) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) return;\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            s.noisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n            s.feat[q] += d;\n        }\n\n        if (!drill_cells.empty()) {\n            ++iter_mark;\n            if (iter_mark == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                iter_mark = 1;\n            }\n            aff.clear();\n\n            if (oldpl) {\n                for (int id : oldpl->drill_ids) {\n                    if (mark[id] != iter_mark) {\n                        mark[id] = iter_mark;\n                        chg[id] = 0;\n                        aff.push_back(id);\n                    }\n                    chg[id]--;\n                }\n            }\n            for (int id : newpl.drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]++;\n            }\n\n            for (int id : aff) {\n                int oc = s.pred[id];\n                int obs = drill_obs[id];\n                s.exact_err -= (oc - obs) * (oc - obs);\n                s.pred[id] += chg[id];\n                int nc = s.pred[id];\n                s.exact_err += (nc - obs) * (nc - obs);\n            }\n        }\n\n        s.choice[field_idx] = (short)newp;\n    }\n\n    SearchState greedy_random_init() {\n        SearchState s;\n        s.choice.fill(-1);\n        s.feat.assign(Q, 0);\n        s.pred.assign(drill_cells.size(), 0);\n        s.exact_err = 0;\n        for (int obs : drill_obs) s.exact_err += obs * obs;\n        s.noisy = initial_noisy0();\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n        for (int k : order) {\n            struct Cand { int p; int e; double n; };\n            Cand best[4];\n            int bsz = 0;\n\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                int de;\n                double dn;\n                calc_delta_parts(s, k, p, de, dn);\n                int ne = s.exact_err + de;\n                double nn = s.noisy + dn;\n                Cand cur{p, ne, nn};\n\n                int pos = bsz;\n                for (int t = 0; t < bsz; ++t) {\n                    if (better_pair(cur.e, cur.n, best[t].e, best[t].n)) {\n                        pos = t;\n                        break;\n                    }\n                }\n                if (pos < 4) {\n                    for (int t = min(3, bsz); t > pos; --t) best[t] = best[t - 1];\n                    best[pos] = cur;\n                    if (bsz < 4) ++bsz;\n                }\n            }\n\n            if (bsz == 0) continue;\n            int pick = 0;\n            if (bsz >= 2) {\n                int r = rng.next_int(0, min(6, bsz * 2) - 1);\n                pick = min(r / 2, bsz - 1);\n            }\n            apply_change(s, k, best[pick].p);\n        }\n        return s;\n    }\n\n    void local_descent(SearchState& s, int max_sweeps = 4) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < max_sweeps; ++sw) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n            for (int k : order) {\n                int bestp = s.choice[k];\n                int beste = s.exact_err;\n                double bestn = s.noisy;\n\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (!usable_placement(k, p)) continue;\n                    int de;\n                    double dn;\n                    calc_delta_parts(s, k, p, de, dn);\n                    int ne = s.exact_err + de;\n                    double nn = s.noisy + dn;\n                    if (better_pair(ne, nn, beste, bestn)) {\n                        beste = ne;\n                        bestn = nn;\n                        bestp = p;\n                    }\n                }\n                if (bestp != s.choice[k]) {\n                    apply_change(s, k, bestp);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    static bool same_choice(const SavedState& a, const SavedState& b, int M) {\n        for (int i = 0; i < M; ++i) if (a.choice[i] != b.choice[i]) return false;\n        return true;\n    }\n\n    void add_saved(vector<SavedState>& top, const SearchState& s, int keep = 10) {\n        SavedState cur;\n        cur.choice = s.choice;\n        cur.exact_err = s.exact_err;\n        cur.noisy = s.noisy;\n\n        for (auto &x : top) {\n            if (same_choice(x, cur, M)) {\n                if (better_pair(cur.exact_err, cur.noisy, x.exact_err, x.noisy)) x = cur;\n                return;\n            }\n        }\n\n        top.push_back(cur);\n        sort(top.begin(), top.end(), [&](const SavedState& a, const SavedState& b) {\n            return better_pair(a.exact_err, a.noisy, b.exact_err, b.noisy);\n        });\n        if ((int)top.size() > keep) top.resize(keep);\n    }\n\n    vector<SavedState> search_states(int restarts) {\n        vector<SavedState> top;\n        for (int it = 0; it < restarts; ++it) {\n            if (elapsed_ms() > 2650.0) break;\n            SearchState s = greedy_random_init();\n            local_descent(s, 4);\n            add_saved(top, s, 10);\n        }\n        return top;\n    }\n\n    vector<char> union_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ(C, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = choice[k];\n            if (p < 0) continue;\n            for (int id : fields[k].ps[p].cells) occ[id] = 1;\n        }\n        return occ;\n    }\n\n    bool exact_deduce_union(vector<int>& ans_cells) {\n        if (elapsed_ms() > 2520.0) return false;\n        for (int k = 0; k < M; ++k) if (fields[k].valid_count <= 0) return false;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (fields[a].valid_count != fields[b].valid_count) return fields[a].valid_count < fields[b].valid_count;\n            return a < b;\n        });\n\n        double log_prod = 0.0;\n        for (int k : order) log_prod += log((double)max(1, fields[k].valid_count));\n        if (log_prod > log(5.0e6)) return false;\n\n        int D = (int)drill_cells.size();\n        vector<vector<int>> valid_list(M);\n\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (usable_placement(k, p)) valid_list[t].push_back(p);\n            }\n            if (valid_list[t].empty()) return false;\n        }\n\n        vector<vector<int>> can_cover(M, vector<int>(D, 0));\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                for (int did : fields[k].ps[p].drill_ids) can_cover[t][did] = 1;\n            }\n        }\n\n        vector<vector<int>> rem_max(M + 1, vector<int>(D, 0));\n        for (int t = M - 1; t >= 0; --t) {\n            for (int d = 0; d < D; ++d) rem_max[t][d] = rem_max[t + 1][d] + can_cover[t][d];\n        }\n\n        array<short, MAXM> choice;\n        choice.fill(-1);\n        vector<int> cur(D, 0);\n\n        long long nodes = 0;\n        bool aborted = false;\n        int solutions = 0;\n        bool same_union = true;\n        bitset<MAXC> common_union;\n        bool has_common = false;\n\n        function<void(int)> dfs = [&](int t) {\n            if (aborted) return;\n            if (++nodes > 3500000LL || elapsed_ms() > 2870.0) {\n                aborted = true;\n                return;\n            }\n\n            for (int d = 0; d < D; ++d) {\n                if (cur[d] > drill_obs[d]) return;\n                if (cur[d] + rem_max[t][d] < drill_obs[d]) return;\n            }\n\n            if (t == M) {\n                for (int d = 0; d < D; ++d) if (cur[d] != drill_obs[d]) return;\n                solutions++;\n                bitset<MAXC> uni;\n                for (int kk = 0; kk < M; ++kk) {\n                    int p = choice[kk];\n                    uni |= fields[kk].ps[p].mask;\n                }\n                if (!has_common) {\n                    common_union = uni;\n                    has_common = true;\n                } else if (common_union != uni) {\n                    same_union = false;\n                }\n                return;\n            }\n\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                auto &pl = fields[k].ps[p];\n                choice[k] = (short)p;\n                for (int did : pl.drill_ids) cur[did]++;\n                dfs(t + 1);\n                for (int did : pl.drill_ids) cur[did]--;\n                if (aborted) return;\n            }\n        };\n\n        dfs(0);\n\n        if (aborted || solutions == 0 || !same_union) return false;\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (common_union.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    bool confident_answer_from_top(const vector<SavedState>& top, vector<int>& ans_cells) {\n        if (top.empty() || top[0].exact_err != 0) return false;\n\n        vector<int> idxs;\n        for (int i = 0; i < (int)top.size(); ++i) {\n            if (top[i].exact_err == 0) idxs.push_back(i);\n        }\n        if ((int)idxs.size() < 4) return false;\n\n        int use = min(6, (int)idxs.size());\n        auto base = union_from_choice(top[idxs[0]].choice);\n        for (int t = 1; t < use; ++t) {\n            auto u = union_from_choice(top[idxs[t]].choice);\n            if (u != base) return false;\n        }\n\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (base[id]) ans_cells.push_back(id);\n        return true;\n    }\n\n    int select_drill_cell_from_states(const vector<SavedState>& top) {\n        auto possible = compute_possible_union();\n        vector<double> best_score(C, -1e100);\n\n        vector<int> near_pos(C, 0);\n        for (int t = 0; t < (int)drill_cells.size(); ++t) {\n            if (drill_obs[t] <= 0) continue;\n            int id = drill_cells[t];\n            int x = id / N, y = id % N;\n            static const int dx[4] = {-1, 1, 0, 0};\n            static const int dy[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                    int nid = nx * N + ny;\n                    if (exact_v[nid] == -1) near_pos[nid]++;\n                }\n            }\n        }\n\n        if (!top.empty()) {\n            int best_exact = top[0].exact_err;\n            vector<int> cand_idxs;\n            for (int i = 0; i < (int)top.size(); ++i) {\n                if (top[i].exact_err == best_exact) cand_idxs.push_back(i);\n            }\n            if ((int)cand_idxs.size() >= 2) {\n                int S = min(8, (int)cand_idxs.size());\n                vector<double> sum(C, 0.0), sq(C, 0.0), occ(C, 0.0);\n\n                for (int t = 0; t < S; ++t) {\n                    const auto& ch = top[cand_idxs[t]].choice;\n                    vector<int> cnt(C, 0);\n                    for (int k = 0; k < M; ++k) {\n                        int p = ch[k];\n                        if (p < 0) continue;\n                        for (int id : fields[k].ps[p].cells) cnt[id]++;\n                    }\n                    for (int id = 0; id < C; ++id) {\n                        if (exact_v[id] != -1 || !possible.test(id)) continue;\n                        sum[id] += cnt[id];\n                        sq[id] += 1.0 * cnt[id] * cnt[id];\n                        occ[id] += (cnt[id] > 0 ? 1.0 : 0.0);\n                    }\n                }\n\n                for (int id = 0; id < C; ++id) {\n                    if (exact_v[id] != -1 || !possible.test(id)) continue;\n                    double mean = sum[id] / S;\n                    double var = sq[id] / S - mean * mean;\n                    double pocc = occ[id] / S;\n                    double score = var + 0.30 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * mean;\n                    best_score[id] = max(best_score[id], score);\n                }\n            }\n        }\n\n        vector<double> pcover_sum(C, 0.0), var_sum(C, 0.0);\n        vector<int> cnt(C, 0);\n\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count <= 0) continue;\n            fill(cnt.begin(), cnt.end(), 0);\n            int tot = 0;\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                ++tot;\n                for (int id : fields[k].ps[p].cells) cnt[id]++;\n            }\n            if (tot == 0) continue;\n\n            for (int id = 0; id < C; ++id) {\n                if (exact_v[id] != -1 || !possible.test(id)) continue;\n                if (cnt[id] == 0) continue;\n                double pk = 1.0 * cnt[id] / tot;\n                pcover_sum[id] += pk;\n                var_sum[id] += pk * (1.0 - pk);\n            }\n        }\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1 || !possible.test(id)) continue;\n            double p0 = 1.0;\n            for (int k = 0; k < M; ++k) {\n                if (fields[k].valid_count <= 0) continue;\n                int cov = 0;\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (usable_placement(k, p) && fields[k].ps[p].mask.test(id)) cov++;\n                }\n                double pk = 1.0 * cov / max(1, fields[k].valid_count);\n                p0 *= (1.0 - pk);\n            }\n            double pocc = 1.0 - p0;\n            double score = var_sum[id] + 0.40 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * pcover_sum[id];\n            best_score[id] = max(best_score[id], score);\n        }\n\n        int best_cell = -1;\n        double best = -1e100;\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1 || !possible.test(id)) continue;\n            if (best_score[id] > best + 1e-12) {\n                best = best_score[id];\n                best_cell = id;\n            }\n        }\n        if (best_cell != -1) return best_cell;\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1 && possible.test(id)) return id;\n        }\n        return -1;\n    }\n\n    bool should_use_search() const {\n        if (Q == 0) return false;\n        if (M <= 6) return true;\n        if (M <= 9) return true;\n        if (drill_cells.size() >= 3 && M <= 16) return true;\n        if (drill_cells.size() >= 5) return true;\n        return false;\n    }\n\n    bool finish_by_drilling_possible_union_if_tiny(int threshold) {\n        auto rem = possible_union_unknown_cells();\n        if ((int)rem.size() > threshold) return false;\n\n        for (int cell : rem) {\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        return ask_answer(ans);\n    }\n\n    bool heuristic_phase() {\n        int heuristic_limit;\n        if (M <= 4) heuristic_limit = 24;\n        else if (M <= 8) heuristic_limit = 18;\n        else if (M <= 12) heuristic_limit = 12;\n        else heuristic_limit = 8;\n        if (eps <= 0.05) heuristic_limit += 4;\n        heuristic_limit = min(28, heuristic_limit);\n\n        bool guessed_nonexact = false;\n\n        for (int step = 0; step < heuristic_limit; ++step) {\n            if (elapsed_ms() > 2800.0) break;\n\n            vector<int> ans_cells;\n\n            if (all_fields_unique(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            if (exact_deduce_union(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            if (step >= heuristic_limit / 2) {\n                if (finish_by_drilling_possible_union_if_tiny(24)) return true;\n            }\n\n            vector<SavedState> top;\n            if (should_use_search()) {\n                int restarts;\n                if (M <= 5) restarts = 24;\n                else if (M <= 9) restarts = 14;\n                else if (M <= 14) restarts = 8;\n                else restarts = 5;\n                if (step > 0) restarts = max(4, restarts - 2);\n                if (eps <= 0.05) restarts += 2;\n                top = search_states(restarts);\n\n                if (!guessed_nonexact && confident_answer_from_top(top, ans_cells)) {\n                    guessed_nonexact = true;\n                    if (ask_answer(ans_cells)) return true;\n                }\n            }\n\n            int cell = select_drill_cell_from_states(top);\n            if (cell == -1) break;\n\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n            propagate_constraints();\n        }\n\n        vector<int> ans_cells;\n        if (all_fields_unique(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        if (exact_deduce_union(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        return false;\n    }\n\n    void exhaustive_finish() {\n        auto rem = possible_union_unknown_cells();\n        for (int cell : rem) {\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        if (ask_answer(ans)) return;\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1) {\n                int v = ask_drill(id);\n                register_drill(id, v);\n            }\n        }\n        ans.clear();\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        ask_answer(ans);\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_blocks();\n        build_query_sets();\n        if (Q > 0) ask_initial_queries();\n        enumerate_placements();\n\n        if (heuristic_phase()) return;\n        exhaustive_finish();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct RowSol {\n    int l, r, h;\n    vector<vector<int>> w;   // [D][m] minimum widths\n    vector<int> perm;        // left-to-right order of local indices\n    vector<int> qPath;       // which slot absorbs the row slack on each day\n    ll vcost;\n};\n\nstruct Solver {\n    int W, D, N;\n    vector<vector<int>> a;               // [D][N], sorted ascending in input\n\n    // shelf solver data\n    vector<vector<int>> minH;            // minimal feasible shelf height, -1 if impossible\n    vector<ll> quickCostCache;           // cache for quick row cost\n    vector<char> quickCostUsed;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> W >> D >> N;\n        a.assign(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\n        minH.assign(N, vector<int>(N, -1));\n\n        int SZ = N * N * (W + 1);\n        quickCostCache.assign(SZ, 0);\n        quickCostUsed.assign(SZ, 0);\n    }\n\n    static int divup(int x, int y) {\n        return (x + y - 1) / y;\n    }\n\n    static int symdiff_count_sorted(const vector<int>& A, const vector<int>& B) {\n        int i = 0, j = 0, inter = 0;\n        while (i < (int)A.size() && j < (int)B.size()) {\n            if (A[i] == B[j]) {\n                inter++;\n                i++;\n                j++;\n            } else if (A[i] < B[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return (int)A.size() + (int)B.size() - 2 * inter;\n    }\n\n    inline int cache_id(int l, int r, int h) const {\n        return ((l * N + r) * (W + 1) + h);\n    }\n\n    bool feasible_seg(int l, int r, int h) const {\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int k = l; k <= r; k++) {\n                s += divup(a[d][k], h);\n                if (s > W) return false;\n            }\n        }\n        return true;\n    }\n\n    void precompute_min_heights() {\n        for (int l = 0; l < N; l++) {\n            for (int r = l; r < N; r++) {\n                if (!feasible_seg(l, r, W)) break; // larger r also impossible\n                int lo = 1, hi = W;\n                while (lo < hi) {\n                    int mid = (lo + hi) >> 1;\n                    if (feasible_seg(l, r, mid)) hi = mid;\n                    else lo = mid + 1;\n                }\n                minH[l][r] = lo;\n            }\n        }\n    }\n\n    // quick row cost:\n    // - fixed natural order\n    // - full-width row\n    // - all slack goes to the last rectangle\n    ll quick_row_cost(int l, int r, int h) {\n        int id = cache_id(l, r, h);\n        if (quickCostUsed[id]) return quickCostCache[id];\n        quickCostUsed[id] = 1;\n\n        int m = r - l + 1;\n        vector<vector<int>> cuts(D);\n\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int k = l; k < r; k++) {\n                cur += divup(a[d][k], h);\n                cuts[d].push_back(cur);\n            }\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            v += 1LL * h * symdiff_count_sorted(cuts[d - 1], cuts[d]);\n        }\n        quickCostCache[id] = v;\n        return v;\n    }\n\n    vector<pair<int,int>> partition_dp(int rowPenalty) {\n        vector<vector<ll>> dp(N + 1, vector<ll>(W + 1, INF64));\n        vector<vector<short>> parPos(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parH(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n\n        for (int pos = 0; pos < N; pos++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[pos][used] >= INF64 / 4) continue;\n                for (int r = pos; r < N; r++) {\n                    int h = minH[pos][r];\n                    if (h == -1) break;\n                    int nu = used + h;\n                    if (nu > W) continue;\n                    ll cand = dp[pos][used] + quick_row_cost(pos, r, h) + rowPenalty;\n                    if (cand < dp[r + 1][nu]) {\n                        dp[r + 1][nu] = cand;\n                        parPos[r + 1][nu] = (short)pos;\n                        parH[r + 1][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        ll best = INF64;\n        int bestH = -1;\n        for (int h = 0; h <= W; h++) {\n            if (dp[N][h] < best) {\n                best = dp[N][h];\n                bestH = h;\n            }\n        }\n        if (bestH == -1) return {};\n\n        vector<pair<int,int>> rev;\n        int curPos = N, curH = bestH;\n        while (curPos > 0) {\n            int p = parPos[curPos][curH];\n            int ph = parH[curPos][curH];\n            if (p < 0 || ph < 0) return {};\n            rev.push_back({p, curPos - 1});\n            curPos = p;\n            curH = ph;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    ll score_partition_minheight(const vector<pair<int,int>>& parts) {\n        if (parts.empty()) return INF64;\n        int usedH = 0;\n        ll cost = 0;\n        for (auto [l, r] : parts) {\n            int h = minH[l][r];\n            if (h == -1) return INF64;\n            usedH += h;\n            if (usedH > W) return INF64;\n            cost += quick_row_cost(l, r, h);\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> improve_partition(vector<pair<int,int>> parts) {\n        ll cur = score_partition_minheight(parts);\n        if (cur >= INF64 / 4) return parts;\n\n        for (int round = 0; round < 15; round++) {\n            ll best = cur;\n            vector<pair<int,int>> bestParts = parts;\n            int G = (int)parts.size();\n\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n\n                if (l1 < r1) {\n                    auto np = parts;\n                    np[i] = {l1, r1 - 1};\n                    np[i + 1] = {r1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n                if (l2 < r2) {\n                    auto np = parts;\n                    np[i] = {l1, l2};\n                    np[i + 1] = {l2 + 1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n            }\n\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n                vector<pair<int,int>> np;\n                for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                np.push_back({l1, r2});\n                for (int j = i + 2; j < G; j++) np.push_back(parts[j]);\n                ll sc = score_partition_minheight(np);\n                if (sc < best) {\n                    best = sc;\n                    bestParts = np;\n                }\n            }\n\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                if (l == r) continue;\n                for (int c = l; c < r; c++) {\n                    vector<pair<int,int>> np;\n                    for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                    np.push_back({l, c});\n                    np.push_back({c + 1, r});\n                    for (int j = i + 1; j < G; j++) np.push_back(parts[j]);\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) {\n                        best = sc;\n                        bestParts = np;\n                    }\n                }\n            }\n\n            if (best >= cur) break;\n            cur = best;\n            parts = bestParts;\n        }\n        return parts;\n    }\n\n    pair<ll, vector<int>> allocate_heights_quick(const vector<pair<int,int>>& parts) {\n        int G = (int)parts.size();\n        if (G == 0) return {INF64, {}};\n\n        vector<int> hmin(G);\n        int used = 0;\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            hmin[i] = minH[l][r];\n            if (hmin[i] == -1) return {INF64, {}};\n            used += hmin[i];\n        }\n        if (used > W) return {INF64, {}};\n\n        int slack = W - used;\n\n        vector<vector<ll>> addCost(G, vector<ll>(slack + 1, INF64));\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            for (int e = 0; e <= slack; e++) {\n                addCost[i][e] = quick_row_cost(l, r, hmin[i] + e);\n            }\n        }\n\n        vector<vector<ll>> dp(G + 1, vector<ll>(slack + 1, INF64));\n        vector<vector<short>> par(G + 1, vector<short>(slack + 1, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < G; i++) {\n            for (int usedE = 0; usedE <= slack; usedE++) {\n                if (dp[i][usedE] >= INF64 / 4) continue;\n                for (int e = 0; usedE + e <= slack; e++) {\n                    ll cand = dp[i][usedE] + addCost[i][e];\n                    if (cand < dp[i + 1][usedE + e]) {\n                        dp[i + 1][usedE + e] = cand;\n                        par[i + 1][usedE + e] = (short)e;\n                    }\n                }\n            }\n        }\n\n        if (dp[G][slack] >= INF64 / 4) return {INF64, {}};\n\n        vector<int> heights(G);\n        int rem = slack;\n        for (int i = G; i >= 1; i--) {\n            int e = par[i][rem];\n            heights[i - 1] = hmin[i - 1] + e;\n            rem -= e;\n        }\n        return {dp[G][slack], heights};\n    }\n\n    ll eval_perm_cost_fast_last(const vector<vector<int>>& w, const vector<int>& perm, int h) const {\n        int m = (int)perm.size();\n        vector<vector<int>> cuts(D);\n\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int p = 0; p + 1 < m; p++) {\n                int t = perm[p];\n                cur += w[d][t];\n                cuts[d].push_back(cur);\n            }\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            v += 1LL * h * symdiff_count_sorted(cuts[d - 1], cuts[d]);\n        }\n        return v;\n    }\n\n    pair<ll, vector<int>> optimize_slack_path(const vector<vector<int>>& w, const vector<int>& perm, int h) const {\n        int m = (int)perm.size();\n        if (m == 1) {\n            return {0LL, vector<int>(D, 0)};\n        }\n\n        vector<vector<vector<int>>> cuts(D, vector<vector<int>>(m));\n        for (int d = 0; d < D; d++) {\n            vector<int> bw(m);\n            int sumMin = 0;\n            for (int p = 0; p < m; p++) {\n                bw[p] = w[d][perm[p]];\n                sumMin += bw[p];\n            }\n            int slack = W - sumMin;\n\n            vector<int> pref(m - 1);\n            int cur = 0;\n            for (int p = 0; p + 1 < m; p++) {\n                cur += bw[p];\n                pref[p] = cur;\n            }\n\n            for (int q = 0; q < m; q++) {\n                cuts[d][q].resize(m - 1);\n                for (int p = 0; p + 1 < m; p++) {\n                    cuts[d][q][p] = pref[p] + (p >= q ? slack : 0);\n                }\n            }\n        }\n\n        vector<vector<ll>> dp(D, vector<ll>(m, INF64));\n        vector<vector<short>> par(D, vector<short>(m, -1));\n        for (int q = 0; q < m; q++) dp[0][q] = 0;\n\n        for (int d = 1; d < D; d++) {\n            for (int q2 = 0; q2 < m; q2++) {\n                ll best = INF64;\n                int bestq = -1;\n                for (int q1 = 0; q1 < m; q1++) {\n                    ll trans = 1LL * h * symdiff_count_sorted(cuts[d - 1][q1], cuts[d][q2]);\n                    ll cand = dp[d - 1][q1] + trans;\n                    if (cand < best) {\n                        best = cand;\n                        bestq = q1;\n                    }\n                }\n                dp[d][q2] = best;\n                par[d][q2] = (short)bestq;\n            }\n        }\n\n        ll best = INF64;\n        int endq = -1;\n        for (int q = 0; q < m; q++) {\n            if (dp[D - 1][q] < best) {\n                best = dp[D - 1][q];\n                endq = q;\n            }\n        }\n\n        vector<int> path(D);\n        path[D - 1] = endq;\n        for (int d = D - 1; d >= 1; d--) path[d - 1] = par[d][path[d]];\n        return {best, path};\n    }\n\n    RowSol build_row_sol(int l, int r, int h) const {\n        RowSol row;\n        row.l = l;\n        row.r = r;\n        row.h = h;\n        int m = r - l + 1;\n        row.w.assign(D, vector<int>(m));\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < m; t++) {\n                int ww = divup(a[d][l + t], h);\n                row.w[d][t] = ww;\n                s += ww;\n            }\n            (void)s;\n        }\n\n        vector<int> vol(m, 0), avgw(m, 0);\n        for (int t = 0; t < m; t++) {\n            for (int d = 1; d < D; d++) vol[t] += abs(row.w[d][t] - row.w[d - 1][t]);\n            for (int d = 0; d < D; d++) avgw[t] += row.w[d][t];\n        }\n\n        vector<vector<int>> init_orders;\n        auto add_unique = [&](const vector<int>& ord) {\n            for (auto& v : init_orders) if (v == ord) return;\n            init_orders.push_back(ord);\n        };\n\n        vector<int> id(m), rev(m), byVol(m), byAvg(m);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        byVol = id;\n        sort(byVol.begin(), byVol.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            return x < y;\n        });\n\n        byAvg = id;\n        sort(byAvg.begin(), byAvg.end(), [&](int x, int y) {\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            return x < y;\n        });\n\n        add_unique(id);\n        add_unique(rev);\n        add_unique(byVol);\n        reverse(byVol.begin(), byVol.end());\n        add_unique(byVol);\n        add_unique(byAvg);\n        reverse(byAvg.begin(), byAvg.end());\n        add_unique(byAvg);\n\n        vector<vector<int>> candidatePerms;\n        auto add_perm = [&](const vector<int>& p) {\n            for (auto& q : candidatePerms) if (q == p) return;\n            candidatePerms.push_back(p);\n        };\n\n        auto improve_fast = [&](vector<int> perm) -> vector<int> {\n            ll cur = eval_perm_cost_fast_last(row.w, perm, h);\n\n            for (int round = 0; round < 6; round++) {\n                ll best = cur;\n                int bi = -1, bj = -1;\n                for (int i = 0; i < m; i++) {\n                    for (int j = i + 1; j < m; j++) {\n                        swap(perm[i], perm[j]);\n                        ll sc = eval_perm_cost_fast_last(row.w, perm, h);\n                        swap(perm[i], perm[j]);\n                        if (sc < best) {\n                            best = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(perm[bi], perm[bj]);\n                cur = best;\n            }\n\n            for (int round = 0; round < 2; round++) {\n                ll best = cur;\n                vector<int> bestP = perm;\n                for (int i = 0; i < m; i++) {\n                    for (int j = 0; j < m; j++) if (i != j) {\n                        vector<int> np = perm;\n                        int v = np[i];\n                        np.erase(np.begin() + i);\n                        np.insert(np.begin() + j, v);\n                        ll sc = eval_perm_cost_fast_last(row.w, np, h);\n                        if (sc < best) {\n                            best = sc;\n                            bestP = np;\n                        }\n                    }\n                }\n                if (best >= cur) break;\n                cur = best;\n                perm = bestP;\n            }\n            return perm;\n        };\n\n        for (auto ord : init_orders) {\n            add_perm(ord);\n            auto p = improve_fast(ord);\n            add_perm(p);\n            auto rp = p;\n            reverse(rp.begin(), rp.end());\n            add_perm(rp);\n        }\n\n        ll bestCost = INF64;\n        vector<int> bestPerm = id, bestQ(D, 0);\n\n        for (auto& p : candidatePerms) {\n            auto [cost, qPath] = optimize_slack_path(row.w, p, h);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestPerm = p;\n                bestQ = qPath;\n            }\n        }\n\n        row.perm = bestPerm;\n        row.qPath = bestQ;\n        row.vcost = bestCost;\n        return row;\n    }\n\n    vector<vector<Rect>> solve_shelf_candidate() {\n        precompute_min_heights();\n\n        vector<vector<pair<int,int>>> candParts;\n        auto add_parts = [&](vector<pair<int,int>> p) {\n            if (p.empty()) return;\n            bool dup = false;\n            for (auto& q : candParts) if (q == p) dup = true;\n            if (!dup) candParts.push_back(p);\n        };\n\n        vector<int> penalties = {0, 200, 800, 3000, 10000};\n        for (int pen : penalties) {\n            auto p = partition_dp(pen);\n            if (p.empty()) continue;\n            p = improve_partition(p);\n            add_parts(p);\n        }\n\n        if (minH[0][N - 1] != -1) {\n            auto p = vector<pair<int,int>>{{0, N - 1}};\n            p = improve_partition(p);\n            add_parts(p);\n        }\n\n        {\n            int sum = 0;\n            bool ok = true;\n            vector<pair<int,int>> p;\n            for (int k = 0; k < N; k++) {\n                if (minH[k][k] == -1) ok = false;\n                else sum += minH[k][k];\n                p.push_back({k, k});\n            }\n            if (ok && sum <= W) add_parts(p);\n        }\n\n        vector<vector<Rect>> bestAns;\n        ll bestCost = INF64;\n\n        for (auto& parts : candParts) {\n            auto [quickScore, heights] = allocate_heights_quick(parts);\n            if (quickScore >= INF64 / 4) continue;\n\n            int G = (int)parts.size();\n            vector<RowSol> rows;\n            rows.reserve(G);\n            bool ok = true;\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                int h = heights[i];\n                if (!feasible_seg(l, r, h)) {\n                    ok = false;\n                    break;\n                }\n                rows.push_back(build_row_sol(l, r, h));\n            }\n            if (!ok) continue;\n\n            vector<vector<Rect>> ans(D, vector<Rect>(N));\n            int y = 0;\n            for (int i = 0; i < G; i++) {\n                const RowSol& row = rows[i];\n                int m = row.r - row.l + 1;\n                int y0 = y, y1 = y + row.h;\n                y = y1;\n\n                for (int d = 0; d < D; d++) {\n                    int sumMin = 0;\n                    for (int t = 0; t < m; t++) sumMin += row.w[d][t];\n                    int slackW = W - sumMin;\n                    int q = row.qPath[d];\n\n                    int x = 0;\n                    for (int p = 0; p < m; p++) {\n                        int t = row.perm[p];\n                        int k = row.l + t;\n                        int ww = row.w[d][t] + (p == q ? slackW : 0);\n                        ans[d][k] = {y0, x, y1, x + ww};\n                        x += ww;\n                    }\n                    if (x != W) ok = false;\n                }\n            }\n            if (!ok || y != W) continue;\n            if (!validate_answer(ans)) continue;\n\n            ll cost = evaluate_answer(ans);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestAns = std::move(ans);\n            }\n        }\n\n        return bestAns;\n    }\n\n    // ---------- exact answer evaluation / validation ----------\n\n    bool validate_answer(const vector<vector<Rect>>& ans) const {\n        if ((int)ans.size() != D) return false;\n        for (int d = 0; d < D; d++) {\n            if ((int)ans[d].size() != N) return false;\n            for (int k = 0; k < N; k++) {\n                const auto& r = ans[d][k];\n                if (!(0 <= r.i0 && r.i0 < r.i1 && r.i1 <= W)) return false;\n                if (!(0 <= r.j0 && r.j0 < r.j1 && r.j1 <= W)) return false;\n            }\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    const auto& A = ans[d][i];\n                    const auto& B = ans[d][j];\n                    int h = min(A.i1, B.i1) - max(A.i0, B.i0);\n                    int w = min(A.j1, B.j1) - max(A.j0, B.j0);\n                    if (h > 0 && w > 0) return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    ll evaluate_answer(const vector<vector<Rect>>& ans) const {\n        const int HSZ = (W - 1) * W; // interior horizontal segments\n        const int VSZ = W * (W - 1); // interior vertical segments\n\n        vector<unsigned char> prevH(HSZ, 0), prevV(VSZ, 0);\n        vector<unsigned char> curH(HSZ, 0), curV(VSZ, 0);\n\n        ll total = 0;\n\n        auto markH = [&](int i, int j) {\n            // segment (i,j)-(i,j+1), 1<=i<=W-1, 0<=j<W-1\n            curH[(i - 1) * W + j] = 1;\n        };\n        auto markV = [&](int i, int j) {\n            // segment (i,j)-(i+1,j), 0<=i<W-1, 1<=j<=W-1\n            curV[i * (W - 1) + (j - 1)] = 1;\n        };\n\n        for (int d = 0; d < D; d++) {\n            fill(curH.begin(), curH.end(), 0);\n            fill(curV.begin(), curV.end(), 0);\n\n            for (int k = 0; k < N; k++) {\n                const auto& r = ans[d][k];\n                ll area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n                if (area < a[d][k]) total += 100LL * (a[d][k] - area);\n\n                if (r.i0 > 0) {\n                    for (int j = r.j0; j < r.j1; j++) markH(r.i0, j);\n                }\n                if (r.i1 < W) {\n                    for (int j = r.j0; j < r.j1; j++) markH(r.i1, j);\n                }\n                if (r.j0 > 0) {\n                    for (int i = r.i0; i < r.i1; i++) markV(i, r.j0);\n                }\n                if (r.j1 < W) {\n                    for (int i = r.i0; i < r.i1; i++) markV(i, r.j1);\n                }\n            }\n\n            if (d > 0) {\n                for (int i = 0; i < HSZ; i++) total += (prevH[i] != curH[i]);\n                for (int i = 0; i < VSZ; i++) total += (prevV[i] != curV[i]);\n            }\n\n            prevH.swap(curH);\n            prevV.swap(curV);\n        }\n        return total;\n    }\n\n    // ---------- strip-based candidate (from earlier model) ----------\n\n    static ll shortage_cost_day_profile(const vector<int>& demand, const vector<int>& prof_sorted, int W) {\n        ll s = 0;\n        for (int k = 0; k < (int)demand.size(); k++) {\n            ll area = 1LL * W * prof_sorted[k];\n            if (area < demand[k]) s += demand[k] - area;\n        }\n        return 100LL * s;\n    }\n\n    pair<vector<int>, int> make_local_profile(int d) const {\n        vector<int> c(N, 1);\n        int rem = W - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int deficit = a[d][k] - W * c[k];\n                int gain = deficit > 0 ? min(W, deficit) : 0;\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    pair<vector<int>, int> make_global_profile() const {\n        vector<int> c(N, 1);\n        int rem = W - N;\n\n        while (rem > 0) {\n            int bestGain = 0;\n            int bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int gain = 0;\n                for (int d = 0; d < D; d++) {\n                    int deficit = a[d][k] - W * c[k];\n                    if (deficit > 0) gain += min(W, deficit);\n                }\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    ll trans_cost_pref(const int* p1, const int* p2) const {\n        int len = N - 1;\n        int i = 0, j = 0, common = 0;\n        while (i < len && j < len) {\n            if (p1[i] == p2[j]) {\n                common++;\n                i++;\n                j++;\n            } else if (p1[i] < p2[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return 2LL * W * (len - common);\n    }\n\n    ll eval_perm_strip(\n        const vector<int>& perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        ll dpL = locShort[0];\n        ll dpG = globShort[0];\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            ll ndpL = min(dpL + llc, dpG + glc) + locShort[d];\n            ll ndpG = min(dpL + lgc, dpG) + globShort[d];\n\n            dpL = ndpL;\n            dpG = ndpG;\n        }\n        return min(dpL, dpG);\n    }\n\n    vector<int> descend_perm_strip(\n        vector<int> perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        ll cur = eval_perm_strip(perm, locProf, locShort, globProf, globShort);\n        for (int round = 0; round < 20; round++) {\n            ll best = cur;\n            int bi = -1, bj = -1;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    swap(perm[i], perm[j]);\n                    ll sc = eval_perm_strip(perm, locProf, locShort, globProf, globShort);\n                    swap(perm[i], perm[j]);\n                    if (sc < best) {\n                        best = sc;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n            if (bi == -1) break;\n            swap(perm[bi], perm[bj]);\n            cur = best;\n        }\n        return perm;\n    }\n\n    vector<int> choose_best_perm_strip(\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        vector<ll> vol(N, 0), avg(N, 0);\n        for (int k = 0; k < N; k++) {\n            for (int d = 1; d < D; d++) vol[k] += llabs(locProf[d][k] - locProf[d - 1][k]);\n            for (int d = 0; d < D; d++) avg[k] += locProf[d][k];\n        }\n\n        vector<int> id(N), rev(N), v1(N), v2(N);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        iota(v1.begin(), v1.end(), 0);\n        sort(v1.begin(), v1.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avg[x] != avg[y]) return avg[x] < avg[y];\n            return x < y;\n        });\n\n        v2 = v1;\n        reverse(v2.begin(), v2.end());\n\n        vector<vector<int>> inits = {id, rev, v1, v2};\n        vector<vector<int>> uniq;\n        for (auto &p : inits) {\n            bool ok = true;\n            for (auto &q : uniq) if (q == p) ok = false;\n            if (ok) uniq.push_back(p);\n        }\n\n        vector<int> bestPerm = uniq[0];\n        ll bestScore = INF64;\n\n        for (auto p : uniq) {\n            p = descend_perm_strip(p, locProf, locShort, globProf, globShort);\n            ll sc = eval_perm_strip(p, locProf, locShort, globProf, globShort);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestPerm = p;\n            }\n        }\n        bestPerm = descend_perm_strip(bestPerm, locProf, locShort, globProf, globShort);\n        return bestPerm;\n    }\n\n    vector<int> reconstruct_states_strip(\n        const vector<int>& perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        vector<array<ll, 2>> dp(D);\n        vector<array<int, 2>> par(D);\n\n        dp[0][0] = locShort[0];\n        dp[0][1] = globShort[0];\n        par[0][0] = par[0][1] = -1;\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            ll cand0 = dp[d - 1][0] + llc;\n            ll cand1 = dp[d - 1][1] + glc;\n            if (cand0 <= cand1) {\n                dp[d][0] = cand0 + locShort[d];\n                par[d][0] = 0;\n            } else {\n                dp[d][0] = cand1 + locShort[d];\n                par[d][0] = 1;\n            }\n\n            cand0 = dp[d - 1][0] + lgc;\n            cand1 = dp[d - 1][1];\n            if (cand0 <= cand1) {\n                dp[d][1] = cand0 + globShort[d];\n                par[d][1] = 0;\n            } else {\n                dp[d][1] = cand1 + globShort[d];\n                par[d][1] = 1;\n            }\n        }\n\n        vector<int> state(D);\n        state[D - 1] = (dp[D - 1][0] <= dp[D - 1][1] ? 0 : 1);\n        for (int d = D - 1; d >= 1; d--) state[d - 1] = par[d][state[d]];\n        return state;\n    }\n\n    vector<vector<Rect>> solve_strip_candidate() const {\n        vector<vector<int>> locProf(D, vector<int>(N));\n        vector<int> locRem(D, 0);\n        vector<ll> locShort(D, 0);\n\n        for (int d = 0; d < D; d++) {\n            auto [c, rem] = make_local_profile(d);\n            locProf[d] = c;\n            locRem[d] = rem;\n            locShort[d] = shortage_cost_day_profile(a[d], c, W);\n        }\n\n        auto [globProf, globRem] = make_global_profile();\n        vector<ll> globShort(D, 0);\n        for (int d = 0; d < D; d++) {\n            globShort[d] = shortage_cost_day_profile(a[d], globProf, W);\n        }\n\n        vector<int> perm = choose_best_perm_strip(locProf, locShort, globProf, globShort);\n        vector<int> state = reconstruct_states_strip(perm, locProf, locShort, globProf, globShort);\n\n        vector<vector<Rect>> ans(D, vector<Rect>(N));\n\n        for (int d = 0; d < D; d++) {\n            vector<int> x(N);\n            if (state[d] == 0) {\n                for (int i = 0; i < N; i++) x[i] = locProf[d][perm[i]];\n                x[N - 1] += locRem[d];\n            } else {\n                for (int i = 0; i < N; i++) x[i] = globProf[perm[i]];\n                x[N - 1] += globRem;\n            }\n\n            vector<int> top(N), bot(N);\n            int cur = 0;\n            for (int i = 0; i < N; i++) {\n                top[i] = cur;\n                cur += x[i];\n                bot[i] = cur;\n            }\n            if (cur != W) bot[N - 1] += W - cur;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            stable_sort(ord.begin(), ord.end(), [&](int i, int j) {\n                if (x[i] != x[j]) return x[i] < x[j];\n                return i < j;\n            });\n\n            for (int k = 0; k < N; k++) {\n                int idx = ord[k];\n                ans[d][k] = {top[idx], 0, bot[idx], W};\n            }\n        }\n        return ans;\n    }\n\n    vector<vector<Rect>> fallback_answer() const {\n        vector<vector<Rect>> ans(D, vector<Rect>(N));\n        for (int d = 0; d < D; d++) {\n            for (int k = 0; k < N; k++) {\n                ans[d][k] = {k, 0, k + 1, W};\n            }\n        }\n        return ans;\n    }\n\n    void solve() {\n        vector<vector<Rect>> bestAns;\n        ll bestCost = INF64;\n\n        // Candidate 1: shelf-based\n        {\n            auto ans = solve_shelf_candidate();\n            if (!ans.empty() && validate_answer(ans)) {\n                ll cost = evaluate_answer(ans);\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestAns = std::move(ans);\n                }\n            }\n        }\n\n        // Candidate 2: strip-based\n        {\n            auto ans = solve_strip_candidate();\n            if (!ans.empty() && validate_answer(ans)) {\n                ll cost = evaluate_answer(ans);\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestAns = std::move(ans);\n                }\n            }\n        }\n\n        if (bestAns.empty()) bestAns = fallback_answer();\n        if (!validate_answer(bestAns)) bestAns = fallback_answer();\n\n        for (int d = 0; d < D; d++) {\n            for (int k = 0; k < N; k++) {\n                const auto& r = bestAns[d][k];\n                cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 9;\nstatic constexpr int POS = 7;\nstatic constexpr int CELL = 81;\nstatic constexpr int MOD = 998244353;\nstatic constexpr int MAX_A = 20 * 7 * 7; // 980\nstatic constexpr int ELITE_CAP = 4;\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 Action {\n    int m, p, q;\n    array<uint8_t, 9> cell;\n    array<int, 9> val;\n};\n\nstruct Solution {\n    array<int, CELL> r{};\n    array<uint8_t, MAX_A> cnt{};\n    array<long long, MAX_A> add_gain{};\n    vector<uint16_t> ops;\n    int L = 0;\n    long long score = 0;\n};\n\nstruct BestAdd {\n    long long gain = 0;\n    int id = -1;\n};\nstruct BestRemove {\n    long long gain = 0;\n    int id = -1;\n};\nstruct BestPair {\n    long long gain = 0;\n    int a = -1, b = -1;\n};\nstruct BestSwap {\n    long long gain = 0;\n    int rem = -1, add = -1;\n};\nstruct BestExpand12 {\n    long long gain = 0;\n    int rem = -1, a = -1, b = -1;\n};\n\nint M_in, K_in;\narray<int, CELL> init_r;\nvector<Action> actions;\narray<vector<int>, CELL> cell_to_actions;\nint A = 0;\n\narray<int, MAX_A> seen_action{};\nint seen_token = 1;\n\ninline bool action_touches_cell(int aid, int c) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        if (ac.cell[k] == c) return true;\n    }\n    return false;\n}\n\ninline long long calc_add_gain_board(const array<int, CELL>& r, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int v = ac.val[k];\n        delta += (r[idx] + v >= MOD ? (long long)v - MOD : (long long)v);\n    }\n    return delta;\n}\n\ninline long long gain_add(const Solution& s, int aid) {\n    return s.add_gain[aid];\n}\n\ninline long long gain_remove(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int v = ac.val[k];\n        delta += (s.r[idx] < v ? (long long)MOD - v : -(long long)v);\n    }\n    return delta;\n}\n\ninline long long gain_swap(const Solution& s, int rem_id, int add_id) {\n    if (rem_id == add_id) return 0;\n    const auto& rm = actions[rem_id];\n    const auto& ad = actions[add_id];\n\n    long long delta = 0;\n    bool used_ad[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = rm.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv - rm.val[i];\n        if (nv < 0) nv += MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (ad.cell[j] == idx) {\n                nv += ad.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_ad[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_ad[j]) {\n            int idx = ad.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + ad.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline long long gain_add_pair(const Solution& s, int a_id, int b_id) {\n    const auto& a = actions[a_id];\n    const auto& b = actions[b_id];\n\n    long long delta = 0;\n    bool used_b[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = a.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv + a.val[i];\n        if (nv >= MOD) nv -= MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (b.cell[j] == idx) {\n                nv += b.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_b[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_b[j]) {\n            int idx = b.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + b.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline void refresh_affected_by_action(Solution& s, int acted_aid) {\n    if (++seen_token == INT_MAX) {\n        seen_action.fill(0);\n        seen_token = 1;\n    }\n    const auto& ac = actions[acted_aid];\n    for (int k = 0; k < 9; ++k) {\n        int c = ac.cell[k];\n        for (int aid : cell_to_actions[c]) {\n            if (seen_action[aid] == seen_token) continue;\n            seen_action[aid] = seen_token;\n            s.add_gain[aid] = calc_add_gain_board(s.r, aid);\n        }\n    }\n}\n\ninline void apply_add(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    ++s.cnt[aid];\n    s.ops.push_back((uint16_t)aid);\n    ++s.L;\n    refresh_affected_by_action(s, aid);\n}\n\ninline void apply_remove_aid(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n    for (int i = (int)s.ops.size() - 1; i >= 0; --i) {\n        if ((int)s.ops[i] == aid) {\n            s.ops[i] = s.ops.back();\n            s.ops.pop_back();\n            break;\n        }\n    }\n    refresh_affected_by_action(s, aid);\n}\n\ninline void apply_remove_index(Solution& s, int idx_in_ops) {\n    int aid = s.ops[idx_in_ops];\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n    s.ops[idx_in_ops] = s.ops.back();\n    s.ops.pop_back();\n    refresh_affected_by_action(s, aid);\n}\n\nvoid init_all_add_gains(Solution& s) {\n    for (int aid = 0; aid < A; ++aid) {\n        s.add_gain[aid] = calc_add_gain_board(s.r, aid);\n    }\n}\n\nSolution make_base_solution() {\n    Solution s;\n    s.r = init_r;\n    s.cnt.fill(0);\n    s.ops.clear();\n    s.ops.reserve(K_in);\n    s.L = 0;\n    s.score = 0;\n    for (int i = 0; i < CELL; ++i) s.score += s.r[i];\n    init_all_add_gains(s);\n    return s;\n}\n\nBestAdd best_single_add(const Solution& s) {\n    BestAdd res;\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = s.add_gain[aid];\n        if (g > res.gain) {\n            res.gain = g;\n            res.id = aid;\n        }\n    }\n    return res;\n}\n\nBestRemove best_single_remove(const Solution& s) {\n    BestRemove res;\n    for (int aid = 0; aid < A; ++aid) {\n        if (!s.cnt[aid]) continue;\n        long long g = gain_remove(s, aid);\n        if (g > res.gain) {\n            res.gain = g;\n            res.id = aid;\n        }\n    }\n    return res;\n}\n\nvector<pair<long long, int>> top_adds(const Solution& s, int T, bool positive_only = false) {\n    vector<pair<long long, int>> v;\n    v.reserve(A);\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = s.add_gain[aid];\n        if (!positive_only || g > 0) v.push_back({g, aid});\n    }\n    if (v.empty()) return v;\n    if ((int)v.size() > T) {\n        nth_element(v.begin(), v.begin() + T, v.end(),\n                    [](const auto& x, const auto& y) { return x.first > y.first; });\n        v.resize(T);\n    }\n    sort(v.begin(), v.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    return v;\n}\n\nBestPair best_pair_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestPair res;\n    int T = (int)cand.size();\n    for (int i = 0; i < T; ++i) {\n        int a = cand[i].second;\n        for (int j = i; j < T; ++j) {\n            int b = cand[j].second;\n            long long g = gain_add_pair(s, a, b);\n            if (g > res.gain) {\n                res.gain = g;\n                res.a = a;\n                res.b = b;\n            }\n        }\n    }\n    return res;\n}\n\nBestSwap best_swap_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestSwap res;\n    if (s.L == 0) return res;\n\n    vector<int> used_ids;\n    used_ids.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (s.cnt[aid]) used_ids.push_back(aid);\n    }\n\n    for (int rem : used_ids) {\n        for (auto [dummy_gain, add] : cand) {\n            (void)dummy_gain;\n            if (add == rem) continue;\n            long long g = gain_swap(s, rem, add);\n            if (g > res.gain) {\n                res.gain = g;\n                res.rem = rem;\n                res.add = add;\n            }\n        }\n    }\n    return res;\n}\n\nBestExpand12 best_expand_1_to_2(const Solution& s, int top_rem = 4, int top_add = 32) {\n    BestExpand12 res;\n    if (s.L == 0 || s.L > K_in - 1) return res;\n\n    vector<pair<long long, int>> rems;\n    rems.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (!s.cnt[aid]) continue;\n        rems.push_back({gain_remove(s, aid), aid});\n    }\n    sort(rems.begin(), rems.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    if ((int)rems.size() > top_rem) rems.resize(top_rem);\n\n    for (auto [gr, rem] : rems) {\n        Solution t = s;\n        apply_remove_aid(t, rem);\n        auto cand = top_adds(t, top_add, false);\n        auto bp = best_pair_from_candidates(t, cand);\n        long long g = gr + bp.gain;\n        if (g > res.gain) {\n            res.gain = g;\n            res.rem = rem;\n            res.a = bp.a;\n            res.b = bp.b;\n        }\n    }\n    return res;\n}\n\ntemplate <class RNG>\nvoid randomized_fill(Solution& s, RNG& rng, int topT = 18) {\n    while (s.L < K_in) {\n        auto cand = top_adds(s, topT, true);\n        if (cand.empty() || cand[0].first <= 0) break;\n\n        int t = min<int>(8, cand.size());\n        int total_w = t * (t + 1) / 2;\n        int r = (int)(rng() % total_w);\n        int acc = 0;\n        int pick = cand[0].second;\n        for (int i = 0; i < t; ++i) {\n            acc += (t - i);\n            if (r < acc) {\n                pick = cand[i].second;\n                break;\n            }\n        }\n        apply_add(s, pick);\n    }\n}\n\ntemplate <class RNG>\nSolution build_greedy(bool randomized, RNG& rng) {\n    Solution s = make_base_solution();\n    if (!randomized) {\n        while (s.L < K_in) {\n            auto ba = best_single_add(s);\n            if (ba.gain <= 0) break;\n            apply_add(s, ba.id);\n        }\n    } else {\n        randomized_fill(s, rng, 18);\n    }\n    return s;\n}\n\nvoid local_improve(Solution& s, const Timer& timer, double deadline, int max_rounds = 10) {\n    const int TOP_PAIR = 72;\n    const int TOP_SWAP = 160;\n\n    for (int round = 0; round < max_rounds && timer.elapsed() < deadline; ++round) {\n        bool changed = false;\n\n        while (s.L < K_in && timer.elapsed() < deadline) {\n            auto ba = best_single_add(s);\n            if (ba.gain <= 0) break;\n            apply_add(s, ba.id);\n            changed = true;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        long long best_gain = 0;\n        int best_type = 0; // 1 remove, 2 swap, 3 pair, 4 expand\n        int x = -1, y = -1, z = -1;\n\n        auto br = best_single_remove(s);\n        if (br.gain > best_gain) {\n            best_gain = br.gain;\n            best_type = 1;\n            x = br.id;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        auto cand_swap = top_adds(s, TOP_SWAP, false);\n\n        if (s.L > 0) {\n            auto bs = best_swap_from_candidates(s, cand_swap);\n            if (bs.gain > best_gain) {\n                best_gain = bs.gain;\n                best_type = 2;\n                x = bs.rem;\n                y = bs.add;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 2) {\n            vector<pair<long long, int>> cand_pair;\n            int take = min<int>(TOP_PAIR, cand_swap.size());\n            cand_pair.assign(cand_swap.begin(), cand_swap.begin() + take);\n            auto bp = best_pair_from_candidates(s, cand_pair);\n            if (bp.gain > best_gain) {\n                best_gain = bp.gain;\n                best_type = 3;\n                x = bp.a;\n                y = bp.b;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 1 && s.L > 0) {\n            auto be = best_expand_1_to_2(s, 4, 32);\n            if (be.gain > best_gain) {\n                best_gain = be.gain;\n                best_type = 4;\n                x = be.rem;\n                y = be.a;\n                z = be.b;\n            }\n        }\n\n        if (best_gain <= 0) {\n            if (!changed) break;\n            continue;\n        }\n\n        if (best_type == 1) {\n            apply_remove_aid(s, x);\n        } else if (best_type == 2) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n        } else if (best_type == 3) {\n            apply_add(s, x);\n            apply_add(s, y);\n        } else if (best_type == 4) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n            apply_add(s, z);\n        }\n    }\n}\n\ntemplate <class RNG>\nSolution perturb_weak_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, 6);\n        return s;\n    }\n\n    int R = 2 + (int)(rng() % 4);\n    R = min(R, s.L);\n\n    vector<pair<long long, int>> rems;\n    rems.reserve(s.L);\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        int aid = s.ops[i];\n        long long gr = gain_remove(s, aid);\n        rems.push_back({gr, i});\n    }\n    sort(rems.begin(), rems.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n\n    int pool = min<int>(12, rems.size());\n    vector<int> ids(pool);\n    iota(ids.begin(), ids.end(), 0);\n    vector<int> pick_idx;\n    pick_idx.reserve(R);\n\n    for (int t = 0; t < R && !ids.empty(); ++t) {\n        int lim = min<int>(6, ids.size());\n        int total_w = lim * (lim + 1) / 2;\n        int rr = (int)(rng() % total_w);\n        int acc = 0, choose_pos = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (lim - i);\n            if (rr < acc) {\n                choose_pos = i;\n                break;\n            }\n        }\n        int sel = ids[choose_pos];\n        pick_idx.push_back(rems[sel].second);\n        ids.erase(ids.begin() + choose_pos);\n    }\n\n    sort(pick_idx.begin(), pick_idx.end(), greater<int>());\n    for (int idx : pick_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, 6);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_random_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, 6);\n        return s;\n    }\n\n    int R = 2 + (int)(rng() % 6);\n    R = min(R, s.L);\n\n    vector<int> idxs(s.L);\n    iota(idxs.begin(), idxs.end(), 0);\n    shuffle(idxs.begin(), idxs.end(), rng);\n    idxs.resize(R);\n    sort(idxs.begin(), idxs.end(), greater<int>());\n\n    for (int idx : idxs) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, 6);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_cell_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, 6);\n        return s;\n    }\n\n    int c = (int)(rng() % CELL);\n    vector<int> rem_idx;\n    rem_idx.reserve(s.L);\n\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        int aid = s.ops[i];\n        if (action_touches_cell(aid, c)) rem_idx.push_back(i);\n    }\n\n    if (rem_idx.empty()) {\n        int R = min<int>(2 + (int)(rng() % 4), s.L);\n        vector<int> idxs(s.L);\n        iota(idxs.begin(), idxs.end(), 0);\n        shuffle(idxs.begin(), idxs.end(), rng);\n        rem_idx.assign(idxs.begin(), idxs.begin() + R);\n    } else {\n        shuffle(rem_idx.begin(), rem_idx.end(), rng);\n        int cap = 2 + (int)(rng() % 6);\n        if ((int)rem_idx.size() > cap) rem_idx.resize(cap);\n    }\n\n    sort(rem_idx.begin(), rem_idx.end(), greater<int>());\n    rem_idx.erase(unique(rem_idx.begin(), rem_idx.end()), rem_idx.end());\n    for (int idx : rem_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, 6);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_position_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, 6);\n        return s;\n    }\n\n    int p0 = (int)(rng() % POS);\n    int q0 = (int)(rng() % POS);\n    int dist = (rng() % 100 < 65 ? 0 : 1);\n\n    vector<int> rem_idx;\n    rem_idx.reserve(s.L);\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        const auto& ac = actions[s.ops[i]];\n        int d = abs(ac.p - p0) + abs(ac.q - q0);\n        if (d <= dist) rem_idx.push_back(i);\n    }\n\n    if (rem_idx.empty()) {\n        int R = min<int>(2 + (int)(rng() % 4), s.L);\n        vector<int> idxs(s.L);\n        iota(idxs.begin(), idxs.end(), 0);\n        shuffle(idxs.begin(), idxs.end(), rng);\n        rem_idx.assign(idxs.begin(), idxs.begin() + R);\n    } else {\n        shuffle(rem_idx.begin(), rem_idx.end(), rng);\n        int cap = 2 + (int)(rng() % 7); // 2..8\n        if ((int)rem_idx.size() > cap) rem_idx.resize(cap);\n    }\n\n    sort(rem_idx.begin(), rem_idx.end(), greater<int>());\n    rem_idx.erase(unique(rem_idx.begin(), rem_idx.end()), rem_idx.end());\n    for (int idx : rem_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, 6);\n    return s;\n}\n\nvoid update_elites(vector<Solution>& elites, const Solution& cand) {\n    for (const auto& e : elites) {\n        if (e.score == cand.score && e.L == cand.L) return;\n    }\n    elites.push_back(cand);\n    sort(elites.begin(), elites.end(), [](const Solution& a, const Solution& b) {\n        return a.score > b.score;\n    });\n    if ((int)elites.size() > ELITE_CAP) elites.resize(ELITE_CAP);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_in;\n    cin >> N_in >> M_in >> K_in;\n\n    for (int i = 0; i < N_in; ++i) {\n        for (int j = 0; j < N_in; ++j) {\n            cin >> init_r[i * N + j];\n        }\n    }\n\n    vector<array<array<int, 3>, 3>> stamps(M_in);\n    for (int m = 0; m < M_in; ++m) {\n        for (int i = 0; i < 3; ++i) {\n            for (int j = 0; j < 3; ++j) {\n                cin >> stamps[m][i][j];\n            }\n        }\n    }\n\n    actions.clear();\n    actions.reserve(M_in * POS * POS);\n    for (int m = 0; m < M_in; ++m) {\n        for (int p = 0; p <= N_in - 3; ++p) {\n            for (int q = 0; q <= N_in - 3; ++q) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                int t = 0;\n                for (int i = 0; i < 3; ++i) {\n                    for (int j = 0; j < 3; ++j) {\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.val[t] = stamps[m][i][j];\n                        ++t;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n    A = (int)actions.size();\n\n    for (int c = 0; c < CELL; ++c) cell_to_actions[c].clear();\n    for (int aid = 0; aid < A; ++aid) {\n        for (int k = 0; k < 9; ++k) {\n            cell_to_actions[actions[aid].cell[k]].push_back(aid);\n        }\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.86;\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count() ^\n        (uint64_t)(uintptr_t)new int\n    );\n\n    vector<Solution> elites;\n    elites.reserve(ELITE_CAP);\n\n    Solution best = build_greedy(false, rng);\n    local_improve(best, timer, TIME_LIMIT, 8);\n    Solution current = best;\n    update_elites(elites, best);\n\n    while (timer.elapsed() < 0.24 && timer.elapsed() < TIME_LIMIT) {\n        Solution s = build_greedy(true, rng);\n        local_improve(s, timer, TIME_LIMIT, 6);\n        if (s.score > best.score) {\n            best = s;\n            current = s;\n        }\n        update_elites(elites, s);\n    }\n\n    while (timer.elapsed() < TIME_LIMIT) {\n        Solution base;\n        uint64_t rv = rng() % 100;\n        if (rv < 8) {\n            base = build_greedy(true, rng);\n            local_improve(base, timer, TIME_LIMIT, 4);\n        } else if (rv < 38) {\n            base = best;\n        } else if (rv < 68) {\n            base = current;\n        } else {\n            if (elites.empty()) base = best;\n            else base = elites[(size_t)(rng() % elites.size())];\n        }\n\n        Solution cand;\n        uint64_t mode = rng() % 100;\n        if (mode < 35) {\n            cand = perturb_weak_rebuild(base, rng, timer, TIME_LIMIT);\n        } else if (mode < 58) {\n            cand = perturb_random_rebuild(base, rng, timer, TIME_LIMIT);\n        } else if (mode < 79) {\n            cand = perturb_cell_rebuild(base, rng, timer, TIME_LIMIT);\n        } else {\n            cand = perturb_position_rebuild(base, rng, timer, TIME_LIMIT);\n        }\n\n        if (cand.score > best.score) best = cand;\n        update_elites(elites, cand);\n\n        double progress = min(1.0, timer.elapsed() / TIME_LIMIT);\n        long double T0 = 1.5e8L;\n        long double T1 = 4.0e5L;\n        long double temp = T0 * pow(T1 / T0, progress);\n\n        long long diff = cand.score - current.score;\n        bool accept = false;\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            long double prob = expl((long double)diff / temp);\n            long double u = (long double)(rng() >> 11) * (1.0L / (1ULL << 53));\n            if (u < prob) accept = true;\n        }\n\n        if (accept) current = cand;\n        if (current.score > best.score) best = current;\n        update_elites(elites, current);\n        update_elites(elites, best);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (int aid : best.ops) {\n        const auto& ac = actions[aid];\n        cout << ac.m << ' ' << ac.p << ' ' << ac.q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int TOTAL = 25;\nstatic constexpr int DYN_BUF = 5;      // exhausted gates (r,0)\nstatic constexpr int STATIC_BUF = 15;  // cols 1..3\nstatic constexpr int CELL_CNT = 20;    // 5 + 15\nstatic constexpr int INF = 1e9;\nstatic constexpr int UNAVAIL = -2;\nstatic constexpr int EMPTY = -1;\n\nstruct Pos {\n    int r, c;\n};\n\nstatic int mdist(const Pos& a, const Pos& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\n\nstatic vector<char> make_route(Pos cur, Pos dst) {\n    vector<char> res;\n    while (cur.r < dst.r) res.push_back('D'), cur.r++;\n    while (cur.r > dst.r) res.push_back('U'), cur.r--;\n    while (cur.c < dst.c) res.push_back('R'), cur.c++;\n    while (cur.c > dst.c) res.push_back('L'), cur.c--;\n    return res;\n}\n\nstatic string macros_to_plan(const vector<pair<Pos, Pos>>& macros) {\n    string s;\n    Pos cur{0, 0};\n    for (auto [src, dst] : macros) {\n        auto p1 = make_route(cur, src);\n        for (char ch : p1) s.push_back(ch);\n        s.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) s.push_back(ch);\n        s.push_back('Q');\n        cur = dst;\n    }\n    if (s.empty()) s = \".\";\n    return s;\n}\n\nstruct TimeKeeper {\n    chrono::steady_clock::time_point st;\n    double limit_ms;\n    TimeKeeper(double limit_ms_) : st(chrono::steady_clock::now()), limit_ms(limit_ms_) {}\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    double remain_ms() const {\n        return limit_ms - elapsed_ms();\n    }\n    bool timeout() const {\n        return elapsed_ms() >= limit_ms;\n    }\n};\n\n// ============================================================\n// Simulator / evaluator\n// ============================================================\n\nstruct EvaluationResult {\n    bool legal = false;\n    long long score = (1LL << 60);\n};\n\nstruct Simulator {\n    int A[N][N];\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    };\n\n    Simulator(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n    }\n\n    EvaluationResult evaluate(const vector<string>& S) const {\n        int board[N][N];\n        int spawn_ptr[N];\n        bool dispatched[TOTAL];\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n\n        Crane cranes[N];\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n\n        int T = 0;\n        for (auto &s : S) T = max(T, (int)s.size());\n        if (T < 1 || T > 10000) return {};\n\n        vector<int> out_seq[N];\n\n        auto step_spawn = [&]() {\n            for (int r = 0; r < N; r++) {\n                if (spawn_ptr[r] >= N) continue;\n                if (board[r][0] != -1) continue;\n\n                bool blocked = false;\n                for (int i = 0; i < N; i++) {\n                    if (!cranes[i].alive) continue;\n                    if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                        blocked = true;\n                        break;\n                    }\n                }\n                if (blocked) continue;\n\n                board[r][0] = A[r][spawn_ptr[r]];\n                spawn_ptr[r]++;\n            }\n        };\n\n        for (int turn = 0; turn < T; turn++) {\n            step_spawn();\n\n            array<char, N> act;\n            array<int, N> nr, nc;\n            array<bool, N> final_alive, moving;\n\n            for (int i = 0; i < N; i++) {\n                act[i] = (turn < (int)S[i].size() ? S[i][turn] : '.');\n                nr[i] = cranes[i].r;\n                nc[i] = cranes[i].c;\n                final_alive[i] = cranes[i].alive;\n                moving[i] = false;\n            }\n\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) {\n                    if (act[i] != '.') return {};\n                    continue;\n                }\n                char a = act[i];\n                if (a == 'U') nr[i]--, moving[i] = true;\n                else if (a == 'D') nr[i]++, moving[i] = true;\n                else if (a == 'L') nc[i]--, moving[i] = true;\n                else if (a == 'R') nc[i]++, moving[i] = true;\n\n                if (a == 'U' || a == 'D' || a == 'L' || a == 'R') {\n                    if (nr[i] < 0 || nr[i] >= N || nc[i] < 0 || nc[i] >= N) return {};\n                    if (!cranes[i].large && cranes[i].hold != -1 && board[nr[i]][nc[i]] != -1) return {};\n                } else if (a == 'P') {\n                    if (cranes[i].hold != -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] == -1) return {};\n                } else if (a == 'Q') {\n                    if (cranes[i].hold == -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] != -1) return {};\n                } else if (a == 'B') {\n                    if (cranes[i].hold != -1) return {};\n                    final_alive[i] = false;\n                } else if (a == '.') {\n                } else {\n                    return {};\n                }\n            }\n\n            for (int i = 0; i < N; i++) if (final_alive[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j]) {\n                    if (nr[i] == nr[j] && nc[i] == nc[j]) return {};\n                }\n            }\n\n            for (int i = 0; i < N; i++) if (final_alive[i] && moving[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j] && moving[j]) {\n                    if (nr[i] == cranes[j].r && nc[i] == cranes[j].c &&\n                        nr[j] == cranes[i].r && nc[j] == cranes[i].c) {\n                        return {};\n                    }\n                }\n            }\n\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                char a = act[i];\n                if (a == '.') {\n                } else if (a == 'B') {\n                    cranes[i].alive = false;\n                } else if (a == 'P') {\n                    cranes[i].hold = board[cranes[i].r][cranes[i].c];\n                    board[cranes[i].r][cranes[i].c] = -1;\n                } else if (a == 'Q') {\n                    board[cranes[i].r][cranes[i].c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                } else {\n                    cranes[i].r = nr[i];\n                    cranes[i].c = nc[i];\n                }\n            }\n\n            for (int r = 0; r < N; r++) {\n                if (board[r][4] != -1) {\n                    int b = board[r][4];\n                    board[r][4] = -1;\n                    if (b < 0 || b >= TOTAL) return {};\n                    if (dispatched[b]) return {};\n                    dispatched[b] = true;\n                    out_seq[r].push_back(b);\n                }\n            }\n        }\n\n        int M0 = T;\n        int M1 = 0, M2 = 0;\n        int dispatched_count = 0;\n\n        for (int r = 0; r < N; r++) {\n            vector<int> correct;\n            for (int b : out_seq[r]) {\n                dispatched_count++;\n                if (b / 5 != r) M2++;\n                else correct.push_back(b);\n            }\n            for (int i = 0; i < (int)correct.size(); i++) {\n                for (int j = i + 1; j < (int)correct.size(); j++) {\n                    if (correct[i] > correct[j]) M1++;\n                }\n            }\n        }\n\n        int M3 = TOTAL - dispatched_count;\n        long long score = 1LL * M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n        return {true, score};\n    }\n};\n\n// ============================================================\n// One-crane macro search\n// ============================================================\n\nstruct MacroSearch {\n    int A[N][N];\n    array<Pos, CELL_CNT> cell_pos;\n\n    MacroSearch(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        for (int r = 0; r < N; r++) cell_pos[r] = {r, 0}; // dynamic buffers\n        int idx = DYN_BUF;\n        for (int r = 0; r < N; r++) for (int c = 1; c <= 3; c++) cell_pos[idx++] = {r, c};\n    }\n\n    struct Key {\n        uint64_t a, b, c;\n        bool operator==(const Key& o) const { return a == o.a && b == o.b && c == o.c; }\n    };\n    struct KeyHash {\n        size_t operator()(const Key& k) const {\n            uint64_t x = k.a;\n            x ^= k.b + 0x9e3779b97f4a7c15ULL + (x << 6) + (x >> 2);\n            x ^= k.c + 0x9e3779b97f4a7c15ULL + (x << 6) + (x >> 2);\n            return (size_t)x;\n        }\n    };\n\n    struct Action {\n        Pos src, dst;\n    };\n\n    struct State {\n        array<uint8_t, 5> ptr{};\n        array<uint8_t, 5> done{};\n        array<int8_t, CELL_CNT> cell{};\n        uint8_t pos = 0;\n        int g = INF;\n        int parent = -1;\n        Action act;\n    };\n\n    static int pos_to_idx(const Pos& p) { return p.r * 5 + p.c; }\n    static Pos idx_to_pos(int idx) { return Pos{idx / 5, idx % 5}; }\n\n    int current_need(const State& s, int tr) const {\n        return 5 * tr + s.done[tr];\n    }\n\n    static uint64_t enc_cell(int v) {\n        if (v == UNAVAIL) return 30;\n        if (v == EMPTY) return 31;\n        return (uint64_t)v;\n    }\n\n    Key pack(const State& s) const {\n        uint64_t out[3] = {0, 0, 0};\n        int sh = 0;\n        auto add = [&](uint64_t v, int bits) {\n            int idx = sh >> 6;\n            int off = sh & 63;\n            if (off + bits <= 64) {\n                out[idx] |= v << off;\n            } else {\n                int low = 64 - off;\n                out[idx] |= v << off;\n                out[idx + 1] |= v >> low;\n            }\n            sh += bits;\n        };\n        for (int i = 0; i < 5; i++) add(s.ptr[i], 3);\n        for (int i = 0; i < 5; i++) add(s.done[i], 3);\n        add(s.pos, 5);\n        for (int i = 0; i < CELL_CNT; i++) add(enc_cell(s.cell[i]), 5);\n        return {out[0], out[1], out[2]};\n    }\n\n    int heuristic(const State& s) const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int k = s.ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            Pos p = cell_pos[i];\n            h += 2 + abs(p.r - tr) + (4 - p.c);\n        }\n        return h;\n    }\n\n    int visible_need_count(const State& s) const {\n        int cnt = 0;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) cnt++;\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b == current_need(s, tr)) cnt++;\n        }\n        return cnt;\n    }\n\n    int gate_need_count(const State& s) const {\n        int cnt = 0;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int dist_to_best_dispatchable(const State& s) const {\n        Pos cur = idx_to_pos(s.pos);\n        int best = 100;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) best = min(best, mdist(cur, Pos{r, 0}));\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b == current_need(s, tr)) best = min(best, mdist(cur, cell_pos[i]));\n        }\n        return best == 100 ? 0 : best;\n    }\n\n    bool finished(const State& s) const {\n        for (int i = 0; i < 5; i++) if (s.done[i] != 5) return false;\n        return true;\n    }\n\n    vector<int> empty_cells(const State& s) const {\n        vector<int> v;\n        for (int i = 0; i < CELL_CNT; i++) if (s.cell[i] == EMPTY) v.push_back(i);\n        return v;\n    }\n\n    int next_need_gap_after_store(const State& s, int r) const {\n        for (int k = s.ptr[r] + 1; k < N; k++) {\n            int b = A[r][k];\n            int tr = b / 5;\n            if (b == current_need(s, tr)) return k - (s.ptr[r] + 1);\n        }\n        return INF;\n    }\n\n    void enumerate_dispatches(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= N) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.ptr[r]++;\n            if (t.ptr[r] == N) t.cell[r] = EMPTY;\n            Pos src{r, 0}, dst{tr, 4};\n            t.done[tr]++;\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.cell[i] = EMPTY;\n            Pos src = cell_pos[i], dst{tr, 4};\n            t.done[tr]++;\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n    }\n\n    void enumerate_stores(const State& s, vector<State>& nxt, int topK) const {\n        Pos cur = idx_to_pos(s.pos);\n        auto empties = empty_cells(s);\n        if (empties.empty()) return;\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= N) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b == current_need(s, tr)) continue;\n\n            int gap = next_need_gap_after_store(s, r);\n\n            vector<pair<tuple<int,int,int,int>, int>> cand;\n            cand.reserve(empties.size());\n            for (int idx : empties) {\n                Pos d = cell_pos[idx];\n                int local = mdist(Pos{r, 0}, d) + mdist(d, Pos{tr, 4});\n                int rowmis = abs(d.r - tr);\n                int colpref = -d.c;\n                int gapkey = (gap >= INF ? 100 : gap);\n                cand.push_back({{gapkey, local, rowmis, colpref}, idx});\n            }\n            sort(cand.begin(), cand.end());\n\n            int K = min<int>(topK, cand.size());\n            for (int z = 0; z < K; z++) {\n                int idx = cand[z].second;\n                State t = s;\n                t.ptr[r]++;\n                if (t.ptr[r] == N) t.cell[r] = EMPTY;\n                t.cell[idx] = b;\n                Pos src{r, 0}, dst = cell_pos[idx];\n                t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n                t.pos = pos_to_idx(dst);\n                t.act = {src, dst};\n                nxt.push_back(t);\n            }\n        }\n    }\n\n    string reconstruct(const vector<State>& states, int id) const {\n        vector<pair<Pos, Pos>> macros;\n        int cur = id;\n        while (states[cur].parent != -1) {\n            macros.push_back({states[cur].act.src, states[cur].act.dst});\n            cur = states[cur].parent;\n        }\n        reverse(macros.begin(), macros.end());\n        return macros_to_plan(macros);\n    }\n\n    optional<string> solve_astar(TimeKeeper& tk, double local_ms, int state_limit, int topK) const {\n        if (tk.remain_ms() < 80) return nullopt;\n        auto local_start = chrono::steady_clock::now();\n        auto local_elapsed = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - local_start).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 5; i++) init.cell[i] = UNAVAIL;\n        for (int i = 5; i < CELL_CNT; i++) init.cell[i] = EMPTY;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        struct PQNode {\n            int f, g, id;\n            bool operator<(const PQNode& o) const {\n                if (f != o.f) return f > o.f;\n                return g > o.g;\n            }\n        };\n\n        vector<State> states;\n        states.reserve(state_limit + 1000);\n        states.push_back(init);\n\n        unordered_map<Key, int, KeyHash> best;\n        best.reserve(state_limit * 2);\n        best[pack(init)] = 0;\n\n        priority_queue<PQNode> pq;\n        pq.push({heuristic(init), 0, 0});\n\n        while (!pq.empty() &&\n               (int)states.size() < state_limit &&\n               local_elapsed() < local_ms &&\n               !tk.timeout()) {\n            auto [f, g, id] = pq.top();\n            pq.pop();\n            if (states[id].g != g) continue;\n            const State& s = states[id];\n\n            if (finished(s)) return reconstruct(states, id);\n\n            vector<State> nxt;\n            nxt.reserve(96);\n            enumerate_dispatches(s, nxt);\n            enumerate_stores(s, nxt, topK);\n\n            for (State &t : nxt) {\n                t.parent = id;\n                Key k = pack(t);\n                auto it = best.find(k);\n                if (it != best.end()) {\n                    int oid = it->second;\n                    if (states[oid].g <= t.g) continue;\n                    it->second = (int)states.size();\n                } else {\n                    best.emplace(k, (int)states.size());\n                }\n                int h = heuristic(t);\n                states.push_back(t);\n                pq.push({t.g + h, t.g, (int)states.size() - 1});\n            }\n        }\n\n        return nullopt;\n    }\n\n    optional<string> solve_beam(TimeKeeper& tk, double local_ms, int width, int mode, int topK) const {\n        if (tk.remain_ms() < 60) return nullopt;\n        auto local_start = chrono::steady_clock::now();\n        auto local_elapsed = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - local_start).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 5; i++) init.cell[i] = UNAVAIL;\n        for (int i = 5; i < CELL_CNT; i++) init.cell[i] = EMPTY;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        vector<State> states;\n        states.reserve(350000);\n        states.push_back(init);\n\n        auto eval_value = [&](const State& s) -> long long {\n            int h = heuristic(s);\n            int vneed = visible_need_count(s);\n            int gneed = gate_need_count(s);\n            int dnear = dist_to_best_dispatchable(s);\n            long long val = 1LL * s.g + h;\n            if (mode == 0) {\n            } else if (mode == 1) {\n                val -= 3LL * vneed;\n                val -= 2LL * gneed;\n            } else if (mode == 2) {\n                val -= 2LL * vneed;\n                val += dnear;\n            } else if (mode == 3) {\n                val -= 4LL * gneed;\n                val += dnear;\n            } else {\n                val -= 2LL * vneed;\n                val -= 1LL * gneed;\n                val += 2LL * dnear;\n            }\n            return val;\n        };\n\n        vector<int> cur{0};\n        int best_finished = -1;\n        int max_depth = 70;\n\n        for (int depth = 0;\n             depth < max_depth && !cur.empty() && local_elapsed() < local_ms && !tk.timeout();\n             depth++) {\n            unordered_map<Key, pair<long long, int>, KeyHash> mp;\n            mp.reserve(width * 30);\n\n            for (int id : cur) {\n                const State& s = states[id];\n                if (finished(s)) {\n                    if (best_finished == -1 || states[id].g < states[best_finished].g) best_finished = id;\n                    continue;\n                }\n\n                vector<State> nxt;\n                nxt.reserve(96);\n                enumerate_dispatches(s, nxt);\n                enumerate_stores(s, nxt, topK);\n\n                for (State &t : nxt) {\n                    t.parent = id;\n                    int nid = (int)states.size();\n                    states.push_back(t);\n\n                    if (finished(t)) {\n                        if (best_finished == -1 || t.g < states[best_finished].g) best_finished = nid;\n                        continue;\n                    }\n\n                    Key k = pack(t);\n                    long long ev = eval_value(t);\n                    auto it = mp.find(k);\n                    if (it == mp.end() || ev < it->second.first ||\n                        (ev == it->second.first && t.g < states[it->second.second].g)) {\n                        mp[k] = {ev, nid};\n                    }\n                }\n            }\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(mp.size());\n            for (auto &kv : mp) cand.push_back({kv.second.first, kv.second.second});\n            sort(cand.begin(), cand.end(), [&](auto &x, auto &y) {\n                if (x.first != y.first) return x.first < y.first;\n                return states[x.second].g < states[y.second].g;\n            });\n\n            cur.clear();\n            for (int i = 0; i < (int)cand.size() && i < width; i++) cur.push_back(cand[i].second);\n\n            if (best_finished != -1 && depth >= 20) break;\n        }\n\n        if (best_finished != -1) return reconstruct(states, best_finished);\n        return nullopt;\n    }\n};\n\n// ============================================================\n// Greedy solver\n// ============================================================\n\nstruct GreedyParam {\n    int dispatch_mode = 0;\n    int store_mode = 0;\n    int unlock_bonus = 0;\n};\n\nstruct GreedySolver {\n    int A[N][N];\n    GreedyParam param;\n\n    int board[N][N];\n    int spawn_ptr[N];\n    bool dispatched[TOTAL];\n    int total_dispatched = 0;\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    } cranes[N];\n\n    string out[N];\n    deque<char> plan;\n\n    GreedySolver(int A_[N][N], GreedyParam p) : param(p) {\n        memcpy(A, A_, sizeof(A));\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n    }\n\n    int current_need(int tr) const {\n        for (int x = 5 * tr; x < 5 * tr + 5; x++) if (!dispatched[x]) return x;\n        return 5 * tr + 5;\n    }\n\n    int inversion_increase_if_dispatch_now(int b) const {\n        int tr = b / 5;\n        int cnt = 0;\n        for (int x = 5 * tr; x < b; x++) if (!dispatched[x]) cnt++;\n        return cnt;\n    }\n\n    int remaining_lb() const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= 3; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + (4 - c);\n            }\n        }\n        for (int r = 0; r < N; r++) {\n            for (int k = spawn_ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        return h;\n    }\n\n    deque<char> make_transport_plan(Pos src, Pos dst) const {\n        deque<char> q;\n        auto p1 = make_route(Pos{cranes[0].r, cranes[0].c}, src);\n        for (char ch : p1) q.push_back(ch);\n        q.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) q.push_back(ch);\n        q.push_back('Q');\n        return q;\n    }\n\n    bool is_buffer_cell_empty(int r, int c) const {\n        if (c == 4) return false;\n        if (board[r][c] != -1) return false;\n        if (1 <= c && c <= 3) return true;\n        if (c == 0 && spawn_ptr[r] == N) return true;\n        return false;\n    }\n\n    vector<Pos> available_buffer_cells() const {\n        vector<Pos> v;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) if (is_buffer_cell_empty(r, c)) v.push_back({r, c});\n            if (is_buffer_cell_empty(r, 0)) v.push_back({r, 0});\n        }\n        return v;\n    }\n\n    int next_need_gap_after_storing_row(int r) const {\n        for (int k = spawn_ptr[r]; k < N; k++) {\n            int b = A[r][k];\n            int tr = b / 5;\n            if (!dispatched[b] && b == current_need(tr)) return k - spawn_ptr[r];\n        }\n        return INF;\n    }\n\n    struct Cand {\n        long long k1 = (1LL << 60), k2 = (1LL << 60), k3 = (1LL << 60);\n        Pos src{-1, -1}, dst{-1, -1};\n        bool ok = false;\n    };\n\n    optional<deque<char>> choose_dispatch_plan() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b != current_need(tr)) continue;\n\n            Pos src{r, c}, dst{tr, 4};\n            int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            int after_h = base_h - (2 + abs(r - tr) + (4 - c));\n\n            long long k1, k2, k3;\n            if (param.dispatch_mode == 0) {\n                k1 = immediate;\n                k2 = (c == 0 ? 0 : 1);\n                k3 = after_h;\n            } else if (param.dispatch_mode == 1) {\n                k1 = immediate + after_h;\n                k2 = immediate;\n                k3 = (c == 0 ? 0 : 1);\n            } else if (param.dispatch_mode == 2) {\n                k1 = immediate + after_h - (c == 0 ? 3 : 0);\n                k2 = immediate;\n                k3 = after_h;\n            } else {\n                k1 = abs(cur.r - r);\n                k2 = immediate;\n                k3 = after_h;\n            }\n\n            if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                best = {k1, k2, k3, src, dst, true};\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_store_plan() const {\n        auto buf = available_buffer_cells();\n        if (buf.empty()) return nullopt;\n\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) {\n            if (board[r][0] == -1) continue;\n            if (spawn_ptr[r] == N) continue;\n\n            int b = board[r][0];\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n\n            int gap = next_need_gap_after_storing_row(r);\n            int unlock = (gap >= INF ? 0 : max(0, 5 - gap));\n            int old_cost = 2 + abs(r - tr) + 4;\n\n            for (auto d : buf) {\n                int new_cost = 2 + abs(d.r - tr) + (4 - d.c);\n                int immediate = mdist(cur, Pos{r, 0}) + 1 + mdist(Pos{r, 0}, d) + 1;\n                int after_h = base_h - old_cost + new_cost;\n\n                long long k1, k2, k3;\n                if (param.store_mode == 0) {\n                    k1 = gap;\n                    k2 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k3 = new_cost;\n                } else if (param.store_mode == 1) {\n                    k1 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k2 = gap;\n                    k3 = new_cost;\n                } else if (param.store_mode == 2) {\n                    k1 = immediate;\n                    k2 = gap;\n                    k3 = after_h;\n                } else {\n                    k1 = new_cost;\n                    k2 = gap;\n                    k3 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                }\n\n                if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                    best = {k1, k2, k3, Pos{r, 0}, d, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_forced_early_dispatch() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n\n            int inv = inversion_increase_if_dispatch_now(b);\n            Pos src{r, c}, dst{tr, 4};\n            int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            long long k1 = inv;\n            long long k2 = immediate;\n            long long k3 = (c == 0 ? 0 : 1);\n\n            if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                best = {k1, k2, k3, src, dst, true};\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    deque<char> choose_next_plan() const {\n        if (auto p = choose_dispatch_plan()) return *p;\n        if (auto p = choose_store_plan()) return *p;\n        if (auto p = choose_forced_early_dispatch()) return *p;\n        return {};\n    }\n\n    void step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (blocked) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n    }\n\n    void apply_action(int idx, char act) {\n        auto &cr = cranes[idx];\n        if (!cr.alive) return;\n        if (act == '.') return;\n        if (act == 'B') {\n            cr.alive = false;\n            return;\n        }\n        if (act == 'P') {\n            cr.hold = board[cr.r][cr.c];\n            board[cr.r][cr.c] = -1;\n            return;\n        }\n        if (act == 'Q') {\n            board[cr.r][cr.c] = cr.hold;\n            cr.hold = -1;\n            return;\n        }\n        if (act == 'U') cr.r--;\n        if (act == 'D') cr.r++;\n        if (act == 'L') cr.c--;\n        if (act == 'R') cr.c++;\n    }\n\n    void step_dispatch() {\n        for (int r = 0; r < N; r++) {\n            if (board[r][4] != -1) {\n                int b = board[r][4];\n                board[r][4] = -1;\n                if (!dispatched[b]) {\n                    dispatched[b] = true;\n                    total_dispatched++;\n                }\n            }\n        }\n    }\n\n    vector<string> solve() {\n        int turn = 0;\n        while (total_dispatched < TOTAL && turn < 10000) {\n            step_spawn();\n\n            array<char, N> act;\n            act.fill('.');\n            if (turn == 0) {\n                for (int i = 1; i < N; i++) act[i] = 'B';\n            }\n\n            if (plan.empty()) plan = choose_next_plan();\n            if (!plan.empty()) {\n                act[0] = plan.front();\n                plan.pop_front();\n            }\n\n            for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n            for (int i = 0; i < N; i++) apply_action(i, act[i]);\n            step_dispatch();\n            turn++;\n        }\n\n        vector<string> res(N);\n        for (int i = 0; i < N; i++) res[i] = out[i];\n        if (res[0].empty()) res[0] = \".\";\n        for (int i = 1; i < N; i++) if (res[i].empty()) res[i] = \"B\";\n        return res;\n    }\n};\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A[i][j];\n\n    TimeKeeper tk(2800.0);\n    Simulator sim(A);\n    MacroSearch ms(A);\n\n    vector<vector<string>> candidates;\n    vector<string> baseline_candidate;\n\n    auto normalize_join = [&](const vector<string>& S) -> string {\n        string t;\n        for (int i = 0; i < N; i++) {\n            t += S[i];\n            t.push_back('#');\n        }\n        return t;\n    };\n\n    unordered_set<string> seen;\n    seen.reserve(256);\n\n    auto add_candidate = [&](const vector<string>& cand) {\n        string key = normalize_join(cand);\n        if (seen.insert(key).second) candidates.push_back(cand);\n    };\n\n    auto add_onecrane_plan = [&](const optional<string>& plan) {\n        if (!plan.has_value()) return;\n        vector<string> S(N);\n        S[0] = *plan;\n        for (int i = 1; i < N; i++) S[i] = \"B\";\n        add_candidate(S);\n    };\n\n    // Curated greedy portfolio: smaller but stronger than broad brute force\n    vector<GreedyParam> params = {\n        {0, 0, 4},\n        {1, 0, 5},\n        {1, 1, 6},\n        {2, 1, 4},\n        {0, 2, 3},\n        {3, 3, 5},\n        {2, 0, 5},\n        {1, 3, 4},\n        {0, 1, 2},\n        {2, 2, 6},\n        {3, 0, 4},\n        {3, 1, 6},\n        {1, 2, 4},\n        {2, 3, 2},\n    };\n\n    bool first = true;\n    for (auto p : params) {\n        if (tk.timeout()) break;\n        GreedySolver gs(A, p);\n        auto cand = gs.solve();\n        if (first) {\n            baseline_candidate = cand;\n            first = false;\n        }\n        add_candidate(cand);\n    }\n\n    // Restore previously strong exact / beam portfolio\n    add_onecrane_plan(ms.solve_astar(tk, 650.0, 320000, 6));\n    add_onecrane_plan(ms.solve_astar(tk, 450.0, 220000, 8));\n    add_onecrane_plan(ms.solve_beam(tk, 280.0, 1400, 0, 6));\n    add_onecrane_plan(ms.solve_beam(tk, 280.0, 1600, 1, 6));\n    add_onecrane_plan(ms.solve_beam(tk, 280.0, 1600, 2, 7));\n    add_onecrane_plan(ms.solve_beam(tk, 250.0, 1600, 3, 7));\n    add_onecrane_plan(ms.solve_beam(tk, 280.0, 1800, 4, 7));\n\n    long long best_score = (1LL << 60);\n    vector<string> best_ans;\n\n    for (auto &cand : candidates) {\n        auto ev = sim.evaluate(cand);\n        if (!ev.legal) continue;\n        if (ev.score < best_score) {\n            best_score = ev.score;\n            best_ans = cand;\n        }\n    }\n\n    if (best_ans.empty()) best_ans = baseline_candidate;\n\n    for (int i = 0; i < N; i++) {\n        cout << best_ans[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Solver {\n    int N, M;\n    vector<int> val;\n    vector<int> nz_ids;\n    vector<int> pos_ids;\n    int dmat[400][400];\n\n    ll best_var = INF64;\n    int best_kind = -1; // 0 = circular order, 1 = tree\n    vector<int> best_circle;\n    int best_start = 0;\n\n    struct TreePlan {\n        int root = -1;\n        int orient = 0;\n        vector<vector<int>> children;\n        vector<int> parent, sum, sz;\n        ll var_cost = INF64;\n    } best_tree;\n\n    vector<pair<ll, vector<int>>> seed_pool;\n    unordered_set<uint64_t> seed_hashes;\n\n    vector<string> ans;\n    int cur_r = 0, cur_c = 0;\n    ll truck = 0;\n\n    chrono::steady_clock::time_point global_deadline;\n\n    Solver(int N_, const vector<vector<int>>& h) : N(N_) {\n        M = N * N;\n        val.assign(M, 0);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                val[v] = h[r][c];\n                if (val[v] != 0) nz_ids.push_back(v);\n                if (val[v] > 0) pos_ids.push_back(v);\n            }\n        }\n        for (int a = 0; a < M; ++a) {\n            auto [ra, ca] = rc(a);\n            for (int b = 0; b < M; ++b) {\n                auto [rb, cb] = rc(b);\n                dmat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    int id(int r, int c) const { return r * N + c; }\n    pair<int,int> rc(int v) const { return {v / N, v % N}; }\n    int dist0(int v) const { return dmat[0][v]; }\n    int dist(int a, int b) const { return dmat[a][b]; }\n\n    static bool time_over(const chrono::steady_clock::time_point& end_time) {\n        return chrono::steady_clock::now() >= end_time;\n    }\n\n    // ============================================================\n    // Circular-order evaluation\n    // ============================================================\n    struct EvalRes {\n        ll cost;\n        int start;\n    };\n\n    EvalRes eval_circle(const vector<int>& seq) const {\n        int K = (int)seq.size();\n        if (K == 0) return {0, 0};\n\n        static ll pref[405];\n        static int ed[405];\n\n        pref[0] = 0;\n        for (int i = 0; i < K; ++i) pref[i + 1] = pref[i] + val[seq[i]];\n\n        ll mn = pref[0];\n        for (int s = 1; s < K; ++s) mn = min(mn, pref[s]);\n\n        ll total_edge = 0;\n        ll loaded_const = 0;\n        for (int i = 0; i < K; ++i) {\n            int j = (i + 1 == K ? 0 : i + 1);\n            ed[i] = dist(seq[i], seq[j]);\n            total_edge += ed[i];\n            loaded_const += (pref[i + 1] - mn) * 1LL * ed[i];\n        }\n\n        ll best = INF64;\n        int bestS = 0;\n        for (int s = 0; s < K; ++s) {\n            if (pref[s] != mn) continue;\n            int omitted = ed[(s - 1 + K) % K];\n            ll var = 100LL * (total_edge - omitted + dist0(seq[s])) + loaded_const;\n            if (var < best) {\n                best = var;\n                bestS = s;\n            }\n        }\n        return {best, bestS};\n    }\n\n    void update_best_circle(const vector<int>& seq, const EvalRes& ev) {\n        if (ev.cost < best_var) {\n            best_var = ev.cost;\n            best_kind = 0;\n            best_circle = seq;\n            best_start = ev.start;\n        }\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : seq) {\n            uint64_t z = (uint64_t)(x + 1) * 0x9e3779b97f4a7c15ULL;\n            h ^= z;\n            h *= 1099511628211ULL;\n        }\n        h ^= (uint64_t)seq.size() + 0x517cc1b727220a95ULL;\n        return h;\n    }\n\n    void add_seed_if_new(const vector<int>& seq, ll cost) {\n        uint64_t h = hash_seq(seq);\n        if (seed_hashes.insert(h).second) {\n            seed_pool.push_back({cost, seq});\n        }\n    }\n\n    void consider_circle(const vector<int>& seq) {\n        EvalRes ev = eval_circle(seq);\n        update_best_circle(seq, ev);\n        add_seed_if_new(seq, ev.cost);\n    }\n\n    // ============================================================\n    // Base order generators\n    // ============================================================\n    pair<int,int> transform_point(pair<int,int> p, int flip, int rot) const {\n        int r = p.first, c = p.second;\n        if (flip) c = N - 1 - c;\n        for (int k = 0; k < rot; ++k) {\n            int nr = c;\n            int nc = N - 1 - r;\n            r = nr;\n            c = nc;\n        }\n        return {r, c};\n    }\n\n    vector<int> transform_and_compress(const vector<pair<int,int>>& base, int flip, int rot, bool rev) const {\n        vector<int> seq;\n        seq.reserve(nz_ids.size());\n        if (!rev) {\n            for (auto p : base) {\n                auto q = transform_point(p, flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        } else {\n            for (int i = (int)base.size() - 1; i >= 0; --i) {\n                auto q = transform_point(base[i], flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_row_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            if ((r & 1) == 0) {\n                for (int c = 0; c < N; ++c) seq.push_back({r, c});\n            } else {\n                for (int c = N - 1; c >= 0; --c) seq.push_back({r, c});\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_canonical_cycle_like() const {\n        vector<pair<int,int>> cyc;\n        cyc.reserve(M);\n        for (int c = 0; c < N; ++c) cyc.push_back({0, c});\n        for (int r = 1; r < N; ++r) {\n            if (r & 1) {\n                for (int c = N - 1; c >= 1; --c) cyc.push_back({r, c});\n            } else {\n                for (int c = 1; c < N; ++c) cyc.push_back({r, c});\n            }\n        }\n        for (int r = N - 1; r >= 1; --r) cyc.push_back({r, 0});\n        return cyc;\n    }\n\n    vector<pair<int,int>> make_diag_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            vector<pair<int,int>> tmp;\n            int r0 = max(0, s - (N - 1));\n            int r1 = min(N - 1, s);\n            for (int r = r0; r <= r1; ++r) tmp.push_back({r, s - r});\n            if (s & 1) reverse(tmp.begin(), tmp.end());\n            for (auto p : tmp) seq.push_back(p);\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_block_snake(int B) const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        vector<int> block_cols;\n        for (int bc = 0; bc < N; bc += B) block_cols.push_back(bc);\n\n        for (int br = 0; br < N; br += B) {\n            auto bcs = block_cols;\n            if (((br / B) & 1) == 1) reverse(bcs.begin(), bcs.end());\n            for (int bc : bcs) {\n                int rlim = min(N, br + B);\n                int clim = min(N, bc + B);\n                for (int r = br; r < rlim; ++r) {\n                    if (((r - br) & 1) == 0) {\n                        for (int c = bc; c < clim; ++c) seq.push_back({r, c});\n                    } else {\n                        for (int c = clim - 1; c >= bc; --c) seq.push_back({r, c});\n                    }\n                }\n            }\n        }\n        return seq;\n    }\n\n    static void hilbert_rot(int n, int &x, int &y, int rx, int ry) {\n        if (ry == 0) {\n            if (rx == 1) {\n                x = n - 1 - x;\n                y = n - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    static int hilbert_xy2d(int n, int x, int y) {\n        int rx, ry, s, d = 0;\n        for (s = n / 2; s > 0; s /= 2) {\n            rx = (x & s) ? 1 : 0;\n            ry = (y & s) ? 1 : 0;\n            d += s * s * ((3 * rx) ^ ry);\n            hilbert_rot(n, x, y, rx, ry);\n        }\n        return d;\n    }\n\n    static unsigned morton_xy2d(unsigned x, unsigned y) {\n        auto part1by1 = [](unsigned x) -> unsigned {\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        };\n        return (part1by1(y) << 1) | part1by1(x);\n    }\n\n    vector<pair<int,int>> make_hilbert_order() const {\n        vector<pair<int, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        int S = 32;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int d = hilbert_xy2d(S, c, r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) { return a.first < b.first; });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_morton_order() const {\n        vector<pair<unsigned, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                unsigned d = morton_xy2d((unsigned)c, (unsigned)r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) { return a.first < b.first; });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_spiral() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; ++c) seq.push_back({top, c});\n            ++top;\n            for (int r = top; r <= bottom; ++r) seq.push_back({r, right});\n            --right;\n            if (top <= bottom) {\n                for (int c = right; c >= left; --c) seq.push_back({bottom, c});\n                --bottom;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; --r) seq.push_back({r, left});\n                ++left;\n            }\n        }\n        return seq;\n    }\n\n    void try_geometric_orders() {\n        vector<vector<pair<int,int>>> bases;\n        bases.push_back(make_row_snake());\n        bases.push_back(make_canonical_cycle_like());\n        bases.push_back(make_diag_snake());\n        bases.push_back(make_block_snake(2));\n        bases.push_back(make_block_snake(4));\n        bases.push_back(make_block_snake(5));\n        bases.push_back(make_hilbert_order());\n        bases.push_back(make_morton_order());\n        bases.push_back(make_spiral());\n\n        for (const auto& base : bases) {\n            for (int flip = 0; flip < 2; ++flip) {\n                for (int rot = 0; rot < 4; ++rot) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        auto seq = transform_and_compress(base, flip, rot, rev);\n                        consider_circle(seq);\n                    }\n                }\n            }\n        }\n    }\n\n    void try_projection_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        vector<pair<int,int>> coeffs = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {2,-1}, {1,-2}\n        };\n\n        for (auto [a, b] : coeffs) {\n            for (int sr : {-1, 1}) {\n                for (int sc : {-1, 1}) {\n                    vector<int> seq = nz_ids;\n                    sort(seq.begin(), seq.end(), [&](int x, int y) {\n                        auto [rx, cx] = rc(x);\n                        auto [ry, cy] = rc(y);\n                        int p1 = a * sr * rx + b * sc * cx;\n                        int p2 = a * sr * ry + b * sc * cy;\n                        if (p1 != p2) return p1 < p2;\n                        int q1 = b * sr * rx - a * sc * cx;\n                        int q2 = b * sr * ry - a * sc * cy;\n                        if (q1 != q2) return q1 < q2;\n                        return x < y;\n                    });\n                    consider_circle(seq);\n                    reverse(seq.begin(), seq.end());\n                    consider_circle(seq);\n                }\n            }\n        }\n    }\n\n    // ============================================================\n    // Greedy constructors\n    // ============================================================\n    vector<int> select_greedy_starts() const {\n        vector<int> starts;\n        vector<char> seen(M, 0);\n\n        auto add = [&](int v) {\n            if (v == -1) {\n                starts.push_back(v);\n                return;\n            }\n            if (!seen[v]) {\n                seen[v] = 1;\n                starts.push_back(v);\n            }\n        };\n\n        add(-1);\n\n        if ((int)pos_ids.size() <= 40) {\n            for (int v : pos_ids) add(v);\n            return starts;\n        }\n\n        vector<int> tmp = pos_ids;\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (val[a] != val[b]) return val[a] > val[b];\n            return dist0(a) < dist0(b);\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (dist0(a) != dist0(b)) return dist0(a) < dist0(b);\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            int sa = 5 * val[a] - 3 * dist0(a);\n            int sb = 5 * val[b] - 3 * dist0(b);\n            if (sa != sb) return sa > sb;\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        return starts;\n    }\n\n    vector<int> build_greedy_linear(int lambda, int start_id) const {\n        int K = (int)nz_ids.size();\n        vector<char> used(M, 0);\n        vector<int> seq;\n        seq.reserve(K);\n\n        ll load = 0;\n        int cur = -1;\n\n        if (start_id != -1) {\n            used[start_id] = 1;\n            seq.push_back(start_id);\n            load += val[start_id];\n            cur = start_id;\n        }\n\n        while ((int)seq.size() < K) {\n            bool has_feasible_neg = false;\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                if (val[v] < 0 && load >= -1LL * val[v]) {\n                    has_feasible_neg = true;\n                    break;\n                }\n            }\n\n            int best = -1;\n            ll best_score = INF64;\n            int best_d = 0;\n            int best_gain = 0;\n\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                int hv = val[v];\n\n                if (has_feasible_neg) {\n                    if (hv >= 0) continue;\n                    if (load < -1LL * hv) continue;\n                } else {\n                    if (hv <= 0) continue;\n                }\n\n                int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                int gain = abs(hv);\n                ll score;\n                if (hv < 0) score = 1LL * lambda * d - 2LL * gain;\n                else        score = 1LL * lambda * d - 1LL * gain;\n\n                if (best == -1 ||\n                    score < best_score ||\n                    (score == best_score && (d < best_d ||\n                    (d == best_d && gain > best_gain)))) {\n                    best = v;\n                    best_score = score;\n                    best_d = d;\n                    best_gain = gain;\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) {\n                    if (used[v]) continue;\n                    if (val[v] <= 0) continue;\n                    int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                    int gain = abs(val[v]);\n                    ll score = 1LL * lambda * d - gain;\n                    if (best == -1 ||\n                        score < best_score ||\n                        (score == best_score && (d < best_d ||\n                        (d == best_d && gain > best_gain)))) {\n                        best = v;\n                        best_score = score;\n                        best_d = d;\n                        best_gain = gain;\n                    }\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) if (!used[v]) { best = v; break; }\n            }\n\n            used[best] = 1;\n            seq.push_back(best);\n            load += val[best];\n            cur = best;\n        }\n        return seq;\n    }\n\n    void try_greedy_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        vector<int> lambdas = {2, 4, 8, 16, 32};\n        vector<int> starts = select_greedy_starts();\n\n        for (int lambda : lambdas) {\n            for (int st : starts) {\n                auto seq = build_greedy_linear(lambda, st);\n                consider_circle(seq);\n                reverse(seq.begin(), seq.end());\n                consider_circle(seq);\n            }\n        }\n    }\n\n    // ============================================================\n    // TSP-like seeds\n    // ============================================================\n    pair<int,int> farthest_pair(const vector<int>& nodes) const {\n        int a = nodes[0], b = nodes[0];\n        int best = -1;\n        for (int i = 0; i < (int)nodes.size(); ++i) {\n            for (int j = i + 1; j < (int)nodes.size(); ++j) {\n                int d = dist(nodes[i], nodes[j]);\n                if (d > best) {\n                    best = d;\n                    a = nodes[i];\n                    b = nodes[j];\n                }\n            }\n        }\n        return {a, b};\n    }\n\n    vector<int> build_nearest_neighbor_path(int start, int mode) const {\n        int K = (int)nz_ids.size();\n        vector<char> used(M, 0);\n        vector<int> seq;\n        seq.reserve(K);\n        seq.push_back(start);\n        used[start] = 1;\n\n        while ((int)seq.size() < K) {\n            int cur = seq.back();\n            int best = -1;\n            ll bestScore = INF64;\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                int d = dist(cur, v);\n                ll score;\n                if (mode == 0) score = d;\n                else if (mode == 1) score = 8LL * d - abs(val[v]);\n                else score = 16LL * d - 3LL * abs(val[v]);\n                if (best == -1 || score < bestScore ||\n                    (score == bestScore && d < dist(cur, best))) {\n                    best = v;\n                    bestScore = score;\n                }\n            }\n            used[best] = 1;\n            seq.push_back(best);\n        }\n        return seq;\n    }\n\n    vector<int> build_farthest_insertion_cycle(int mode) const {\n        int K = (int)nz_ids.size();\n        if (K <= 2) return nz_ids;\n\n        auto [a, b] = farthest_pair(nz_ids);\n        vector<int> cyc = {a, b};\n        vector<char> used(M, 0);\n        used[a] = used[b] = 1;\n\n        vector<int> nearest(M, 1e9);\n        for (int v : nz_ids) {\n            if (!used[v]) nearest[v] = min(dist(v, a), dist(v, b));\n        }\n\n        while ((int)cyc.size() < K) {\n            int pick = -1;\n            ll bestKey = -INF64;\n\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                ll key = (mode == 0 ? nearest[v] : 10LL * nearest[v] + abs(val[v]));\n                if (pick == -1 || key > bestKey) {\n                    pick = v;\n                    bestKey = key;\n                }\n            }\n\n            int L = (int)cyc.size();\n            int bestPos = 0;\n            ll bestDelta = INF64;\n            for (int i = 0; i < L; ++i) {\n                int x = cyc[i];\n                int y = cyc[(i + 1) % L];\n                ll delta = dist(x, pick) + dist(pick, y) - dist(x, y);\n                if (mode == 1) delta = 10LL * delta - abs(val[pick]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = i + 1;\n                }\n            }\n\n            cyc.insert(cyc.begin() + bestPos, pick);\n            used[pick] = 1;\n            for (int v : nz_ids) if (!used[v]) nearest[v] = min(nearest[v], dist(v, pick));\n        }\n        return cyc;\n    }\n\n    void try_tsp_like_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        auto fp = farthest_pair(nz_ids);\n        vector<int> starts = {fp.first, fp.second};\n\n        auto gs = select_greedy_starts();\n        for (int v : gs) if (v != -1) starts.push_back(v);\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n        if ((int)starts.size() > 12) starts.resize(12);\n\n        for (int st : starts) {\n            for (int mode = 0; mode < 3; ++mode) {\n                auto seq = build_nearest_neighbor_path(st, mode);\n                consider_circle(seq);\n                reverse(seq.begin(), seq.end());\n                consider_circle(seq);\n            }\n        }\n\n        for (int mode = 0; mode < 2; ++mode) {\n            auto cyc = build_farthest_insertion_cycle(mode);\n            consider_circle(cyc);\n            reverse(cyc.begin(), cyc.end());\n            consider_circle(cyc);\n        }\n    }\n\n    // ============================================================\n    // Cross-tree backup\n    // ============================================================\n    TreePlan build_tree_plan(int rr, int cc, int orient) const {\n        TreePlan tp;\n        tp.root = id(rr, cc);\n        tp.orient = orient;\n        tp.children.assign(M, {});\n        tp.parent.assign(M, -1);\n        tp.sum.assign(M, 0);\n        tp.sz.assign(M, 1);\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                if (v == tp.root) continue;\n\n                int pr = r, pc = c;\n                if (orient == 0) {\n                    if (c != cc) pc += (c < cc ? 1 : -1);\n                    else pr += (r < rr ? 1 : -1);\n                } else {\n                    if (r != rr) pr += (r < rr ? 1 : -1);\n                    else pc += (c < cc ? 1 : -1);\n                }\n\n                int p = id(pr, pc);\n                tp.parent[v] = p;\n                tp.children[p].push_back(v);\n            }\n        }\n\n        function<void(int)> dfs = [&](int v) {\n            tp.sum[v] = val[v];\n            tp.sz[v] = 1;\n            for (int u : tp.children[v]) {\n                dfs(u);\n                tp.sum[v] += tp.sum[u];\n                tp.sz[v] += tp.sz[u];\n            }\n        };\n        dfs(tp.root);\n        return tp;\n    }\n\n    int choose_task(int v, const TreePlan &tp, const vector<int>& tasks,\n                    const vector<char>& used, ll cur_load) const {\n        auto get_delta = [&](int tk) -> ll {\n            if (tk == -1) return val[v];\n            return tp.sum[tk];\n        };\n        auto get_sz = [&](int tk) -> int {\n            if (tk == -1) return 0;\n            return tp.sz[tk];\n        };\n\n        int best_neg = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d >= 0) continue;\n            if (cur_load < -d) continue;\n\n            if (best_neg == -2) {\n                best_neg = i;\n            } else {\n                ll d1 = -get_delta(tasks[i]);\n                ll d2 = -get_delta(tasks[best_neg]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_neg]);\n                bool better = false;\n                if (s1 == 0 && s2 == 0) better = d1 > d2;\n                else if (s1 == 0) better = true;\n                else if (s2 == 0) better = false;\n                else {\n                    __int128 lhs = (__int128)d1 * s2;\n                    __int128 rhs = (__int128)d2 * s1;\n                    if (lhs != rhs) better = lhs > rhs;\n                    else better = d1 > d2;\n                }\n                if (better) best_neg = i;\n            }\n        }\n        if (best_neg != -2) return best_neg;\n\n        int best_pos = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d < 0) continue;\n\n            if (best_pos == -2) {\n                best_pos = i;\n            } else {\n                ll p1 = get_delta(tasks[i]);\n                ll p2 = get_delta(tasks[best_pos]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_pos]);\n                bool better = false;\n                if (p1 == 0 && p2 > 0) better = true;\n                else if (p1 > 0 && p2 == 0) better = false;\n                else if (p1 == 0 && p2 == 0) better = false;\n                else {\n                    if (s1 == 0 && s2 == 0) better = p1 < p2;\n                    else if (s1 == 0) better = false;\n                    else if (s2 == 0) better = true;\n                    else {\n                        __int128 lhs = (__int128)p1 * s2;\n                        __int128 rhs = (__int128)p2 * s1;\n                        if (lhs != rhs) better = lhs < rhs;\n                        else better = p1 < p2;\n                    }\n                }\n                if (better) best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    struct EvalState {\n        ll load = 0;\n        ll loaded_move = 0;\n        bool ok = true;\n    };\n\n    void eval_tree_dfs(int v, const TreePlan &tp, EvalState &st) const {\n        if (!st.ok) return;\n\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, st.load);\n            if (idx < 0) {\n                st.ok = false;\n                return;\n            }\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                int hv = val[v];\n                if (hv < 0 && st.load < -1LL * hv) {\n                    st.ok = false;\n                    return;\n                }\n                st.load += hv;\n                if (st.load < 0) {\n                    st.ok = false;\n                    return;\n                }\n            } else {\n                if (tp.sum[tk] < 0 && st.load < -1LL * tp.sum[tk]) {\n                    st.ok = false;\n                    return;\n                }\n                st.loaded_move += st.load;\n                eval_tree_dfs(tk, tp, st);\n                if (!st.ok) return;\n                st.loaded_move += st.load;\n            }\n        }\n    }\n\n    ll eval_tree_plan(TreePlan &tp) const {\n        EvalState st;\n        eval_tree_dfs(tp.root, tp, st);\n        if (!st.ok || st.load != 0) return INF64;\n\n        auto [rr, cc] = rc(tp.root);\n        ll reposition = rr + cc;\n        ll moves = reposition + 2LL * (M - 1);\n        tp.var_cost = 100LL * moves + st.loaded_move;\n        return tp.var_cost;\n    }\n\n    void try_tree_family() {\n        for (int rr = 0; rr < N; ++rr) {\n            for (int cc = 0; cc < N; ++cc) {\n                for (int orient = 0; orient < 2; ++orient) {\n                    TreePlan tp = build_tree_plan(rr, cc, orient);\n                    ll var = eval_tree_plan(tp);\n                    if (var < best_var) {\n                        best_var = var;\n                        best_kind = 1;\n                        best_tree = move(tp);\n                    }\n                }\n            }\n        }\n    }\n\n    // ============================================================\n    // Local search\n    // ============================================================\n    vector<int> op_insert(const vector<int>& seq, int i, int j) const {\n        vector<int> t = seq;\n        if (i == j) return t;\n        int x = t[i];\n        if (i < j) {\n            for (int p = i; p < j; ++p) t[p] = t[p + 1];\n            t[j] = x;\n        } else {\n            for (int p = i; p > j; --p) t[p] = t[p - 1];\n            t[j] = x;\n        }\n        return t;\n    }\n\n    vector<int> op_block_move(const vector<int>& seq, int l, int r, int pos) const {\n        vector<int> remain;\n        remain.reserve(seq.size());\n        vector<int> block;\n        block.reserve(r - l + 1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (l <= i && i <= r) block.push_back(seq[i]);\n            else remain.push_back(seq[i]);\n        }\n        pos = min(pos, (int)remain.size());\n        vector<int> res;\n        res.reserve(seq.size());\n        for (int i = 0; i < pos; ++i) res.push_back(remain[i]);\n        for (int x : block) res.push_back(x);\n        for (int i = pos; i < (int)remain.size(); ++i) res.push_back(remain[i]);\n        return res;\n    }\n\n    void polish_adjacent(vector<int>& seq, ll& cur_cost,\n                         const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 1) return;\n\n        for (int pass = 0; pass < 3; ++pass) {\n            bool improved = false;\n            for (int i = 0; i + 1 < K; ++i) {\n                if ((i & 31) == 0 && time_over(end_time)) return;\n                swap(seq[i], seq[i + 1]);\n                EvalRes ev = eval_circle(seq);\n                if (ev.cost < cur_cost) {\n                    cur_cost = ev.cost;\n                    improved = true;\n                    update_best_circle(seq, ev);\n                } else {\n                    swap(seq[i], seq[i + 1]);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void polish_short_reverse(vector<int>& seq, ll& cur_cost, int W,\n                              const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 2) return;\n\n        for (int pass = 0; pass < 1; ++pass) {\n            bool improved = false;\n            for (int l = 0; l < K; ++l) {\n                if ((l & 15) == 0 && time_over(end_time)) return;\n                int rlim = min(K - 1, l + W);\n                ll best_here = cur_cost;\n                int best_r = -1;\n                for (int r = l + 1; r <= rlim; ++r) {\n                    vector<int> tmp = seq;\n                    reverse(tmp.begin() + l, tmp.begin() + r + 1);\n                    EvalRes ev = eval_circle(tmp);\n                    if (ev.cost < best_here) {\n                        best_here = ev.cost;\n                        best_r = r;\n                    }\n                }\n                if (best_r != -1) {\n                    reverse(seq.begin() + l, seq.begin() + best_r + 1);\n                    cur_cost = best_here;\n                    improved = true;\n                    EvalRes ev = eval_circle(seq);\n                    update_best_circle(seq, ev);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void polish_window_insert(vector<int>& seq, ll& cur_cost, int W,\n                              const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 1) return;\n\n        for (int pass = 0; pass < 1; ++pass) {\n            bool improved_any = false;\n            for (int i = 0; i < K; ++i) {\n                if ((i & 15) == 0 && time_over(end_time)) return;\n                ll best_here = cur_cost;\n                int best_j = i;\n                int L = max(0, i - W);\n                int R = min(K - 1, i + W);\n                for (int j = L; j <= R; ++j) {\n                    if (j == i) continue;\n                    auto tmp = op_insert(seq, i, j);\n                    EvalRes ev = eval_circle(tmp);\n                    if (ev.cost < best_here) {\n                        best_here = ev.cost;\n                        best_j = j;\n                    }\n                }\n                if (best_j != i) {\n                    seq = op_insert(seq, i, best_j);\n                    cur_cost = best_here;\n                    improved_any = true;\n                    EvalRes ev = eval_circle(seq);\n                    update_best_circle(seq, ev);\n                }\n            }\n            if (!improved_any) break;\n        }\n    }\n\n    void improve_seed(vector<int> seq,\n                      const chrono::steady_clock::time_point& end_time,\n                      mt19937& rng) {\n        int K = (int)seq.size();\n        if (K <= 1) {\n            EvalRes ev = eval_circle(seq);\n            update_best_circle(seq, ev);\n            return;\n        }\n\n        EvalRes cur_ev = eval_circle(seq);\n        ll cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        polish_adjacent(seq, cur_cost, end_time);\n        polish_short_reverse(seq, cur_cost, 8, end_time);\n        polish_window_insert(seq, cur_cost, 6, end_time);\n\n        cur_ev = eval_circle(seq);\n        cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        vector<int> best_local_seq = seq;\n        ll best_local_cost = cur_cost;\n\n        auto local_start = chrono::steady_clock::now();\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        double T0 = 6000.0;\n        double T1 = 1.5;\n        double temp = T0;\n\n        uint64_t iter = 0;\n        while (!time_over(end_time)) {\n            if ((iter & 255ULL) == 0) {\n                auto now = chrono::steady_clock::now();\n                double elapsed = chrono::duration<double>(now - local_start).count();\n                double total = max(1e-6, chrono::duration<double>(end_time - local_start).count());\n                double prog = min(1.0, elapsed / total);\n                temp = T0 * pow(T1 / T0, prog);\n            }\n            ++iter;\n\n            vector<int> tmp = seq;\n            int type = (int)(rng() % 4);\n\n            if (type == 0) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                swap(tmp[i], tmp[j]);\n            } else if (type == 1) {\n                int i = (int)(rng() % K);\n                int span = 1 + (int)(rng() % 18);\n                int dir = (rng() & 1) ? 1 : -1;\n                int j = i + dir * span;\n                if (j < 0 || j >= K || i == j) continue;\n                tmp = op_insert(seq, i, j);\n            } else if (type == 2) {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 20);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                reverse(tmp.begin() + l, tmp.begin() + r + 1);\n            } else {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 8);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                int rem = K - (r - l + 1);\n                int pos = (int)(rng() % (rem + 1));\n                tmp = op_block_move(seq, l, r, pos);\n            }\n\n            EvalRes nev = eval_circle(tmp);\n            ll nv = nev.cost;\n            ll delta = nv - cur_cost;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-(double)delta / temp);\n                if (urd(rng) < prob) accept = true;\n            }\n\n            if (accept) {\n                seq.swap(tmp);\n                cur_cost = nv;\n                cur_ev = nev;\n                if (cur_cost < best_local_cost) {\n                    best_local_cost = cur_cost;\n                    best_local_seq = seq;\n                    update_best_circle(best_local_seq, cur_ev);\n                }\n            }\n\n            if ((iter & 1023ULL) == 0) {\n                polish_adjacent(seq, cur_cost, end_time);\n            }\n        }\n\n        seq = best_local_seq;\n        cur_cost = best_local_cost;\n\n        polish_adjacent(seq, cur_cost, end_time);\n        polish_short_reverse(seq, cur_cost, 8, end_time);\n        polish_window_insert(seq, cur_cost, 6, end_time);\n\n        EvalRes ev = eval_circle(seq);\n        update_best_circle(seq, ev);\n\n        // final light improvement-only hill climb\n        for (int it = 0; it < 3000 && !time_over(end_time); ++it) {\n            vector<int> tmp = seq;\n            int type = (int)(rng() % 3);\n\n            if (type == 0) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                swap(tmp[i], tmp[j]);\n            } else if (type == 1) {\n                int i = (int)(rng() % K);\n                int span = 1 + (int)(rng() % 12);\n                int dir = (rng() & 1) ? 1 : -1;\n                int j = i + dir * span;\n                if (j < 0 || j >= K || i == j) continue;\n                tmp = op_insert(seq, i, j);\n            } else {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 12);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                reverse(tmp.begin() + l, tmp.begin() + r + 1);\n            }\n\n            EvalRes nev = eval_circle(tmp);\n            if (nev.cost < cur_cost) {\n                seq.swap(tmp);\n                cur_cost = nev.cost;\n                update_best_circle(seq, nev);\n            }\n        }\n    }\n\n    void improve_orders_by_local_search() {\n        if (seed_pool.empty()) return;\n\n        sort(seed_pool.begin(), seed_pool.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        // Deep search on only a few best seeds.\n        vector<vector<int>> elites;\n        for (auto& p : seed_pool) {\n            elites.push_back(p.second);\n            if ((int)elites.size() >= 3) break;\n        }\n\n        mt19937 rng(123456789);\n        vector<double> w = {0.62, 0.25, 0.13};\n\n        for (int i = 0; i < (int)elites.size(); ++i) {\n            auto now = chrono::steady_clock::now();\n            if (now >= global_deadline) break;\n\n            long long rem_ns = chrono::duration_cast<chrono::nanoseconds>(global_deadline - now).count();\n            long long alloc_ns = (long long)(rem_ns * w[i]);\n            if (i + 1 == (int)elites.size()) alloc_ns = rem_ns;\n            alloc_ns = max<long long>(alloc_ns, 1LL);\n\n            auto local_end = min(global_deadline, now + chrono::nanoseconds(alloc_ns));\n            improve_seed(elites[i], local_end, rng);\n        }\n    }\n\n    // ============================================================\n    // Output\n    // ============================================================\n    void push_move_char(char ch) {\n        ans.emplace_back(1, ch);\n    }\n\n    void move_to(int tr, int tc) {\n        while (cur_r < tr) { push_move_char('D'); ++cur_r; }\n        while (cur_r > tr) { push_move_char('U'); --cur_r; }\n        while (cur_c < tc) { push_move_char('R'); ++cur_c; }\n        while (cur_c > tc) { push_move_char('L'); --cur_c; }\n    }\n\n    void move_to_id(int v) {\n        auto [r, c] = rc(v);\n        move_to(r, c);\n    }\n\n    void move_edge(int a, int b) {\n        auto [r1, c1] = rc(a);\n        auto [r2, c2] = rc(b);\n        if (r2 == r1 + 1 && c2 == c1) push_move_char('D');\n        else if (r2 == r1 - 1 && c2 == c1) push_move_char('U');\n        else if (r2 == r1 && c2 == c1 + 1) push_move_char('R');\n        else if (r2 == r1 && c2 == c1 - 1) push_move_char('L');\n        else assert(false);\n        cur_r = r2;\n        cur_c = c2;\n    }\n\n    void output_order_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        int K = (int)best_circle.size();\n        if (K == 0) return;\n\n        vector<int> ord;\n        ord.reserve(K);\n        for (int t = 0; t < K; ++t) ord.push_back(best_circle[(best_start + t) % K]);\n\n        move_to_id(ord[0]);\n\n        for (int i = 0; i < K; ++i) {\n            int v = ord[i];\n            auto [r, c] = rc(v);\n            assert(cur_r == r && cur_c == c);\n\n            if (val[v] > 0) {\n                ans.push_back(\"+\" + to_string(val[v]));\n                truck += val[v];\n            } else {\n                assert(truck >= -1LL * val[v]);\n                ans.push_back(\"-\" + to_string(-val[v]));\n                truck += val[v];\n            }\n\n            if (i + 1 < K) move_to_id(ord[i + 1]);\n        }\n        assert(truck == 0);\n    }\n\n    void output_tree_dfs(int v, const TreePlan &tp) {\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, truck);\n            assert(idx >= 0);\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                if (val[v] > 0) {\n                    ans.push_back(\"+\" + to_string(val[v]));\n                    truck += val[v];\n                } else if (val[v] < 0) {\n                    assert(truck >= -1LL * val[v]);\n                    ans.push_back(\"-\" + to_string(-val[v]));\n                    truck += val[v];\n                }\n            } else {\n                move_edge(v, tk);\n                output_tree_dfs(tk, tp);\n                move_edge(tk, v);\n            }\n        }\n    }\n\n    void output_tree_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        auto [rr, cc] = rc(best_tree.root);\n        move_to(rr, cc);\n        output_tree_dfs(best_tree.root, best_tree);\n        assert(truck == 0);\n    }\n\n    // ============================================================\n    // Solve\n    // ============================================================\n    void solve() {\n        global_deadline = chrono::steady_clock::now() + chrono::milliseconds(1850);\n\n        try_geometric_orders();\n        try_projection_orders();\n        try_greedy_orders();\n        try_tsp_like_orders();\n\n        if (!time_over(global_deadline)) try_tree_family();\n        if (!time_over(global_deadline)) improve_orders_by_local_search();\n\n        if (best_kind == 1) output_tree_solution();\n        else output_order_solution();\n\n        assert((int)ans.size() <= 100000);\n        for (auto &s : ans) cout << s << '\\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>> h(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n    }\n\n    Solver solver(N, h);\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Solver {\n    int N, M, T, S;\n    vector<vector<int>> X;\n    vector<int> V;\n\n    vector<vector<int>> neighPos;\n    vector<pair<int,int>> edgesPos;\n    vector<int> posOrder;\n    vector<int> centers;\n\n    XorShift64 rng;\n\n    void build_grid() {\n        int P = N * N;\n        neighPos.assign(P, {});\n        edgesPos.clear();\n\n        auto id = [&](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 p = id(r, c);\n                if (r + 1 < N) {\n                    int q = id(r + 1, c);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n                if (c + 1 < N) {\n                    int q = id(r, c + 1);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n            }\n        }\n\n        vector<int> ps(P);\n        iota(ps.begin(), ps.end(), 0);\n\n        auto degree = [&](int p) { return (int)neighPos[p].size(); };\n        auto dist2_center = [&](int p) {\n            int r = p / N, c = p % N;\n            double cr = (N - 1) / 2.0;\n            double cc = (N - 1) / 2.0;\n            double dr = r - cr;\n            double dc = c - cc;\n            return dr * dr + dc * dc;\n        };\n\n        sort(ps.begin(), ps.end(), [&](int a, int b) {\n            int da = degree(a), db = degree(b);\n            if (da != db) return da > db;\n            double xa = dist2_center(a), xb = dist2_center(b);\n            if (xa != xb) return xa < xb;\n            return a < b;\n        });\n        posOrder = ps;\n\n        // Central 2x2 cells for N=6, but written generally.\n        int r0 = N / 2 - 1, r1 = N / 2;\n        int c0 = N / 2 - 1, c1 = N / 2;\n        centers = {id(r0, c0), id(r0, c1), id(r1, c0), id(r1, c1)};\n    }\n\n    bool read_seed_set() {\n        X.assign(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> X[i][j])) return false;\n            }\n        }\n        return true;\n    }\n\n    struct TurnInfo {\n        vector<double> rarityW;\n        vector<double> uniqBonus;\n        vector<double> weightedScore;\n        vector<double> partnerScore; // relative to eliteMain\n        int eliteMain;\n        int eliteBestV;\n    };\n\n    TurnInfo analyze_turn(int turn) {\n        TurnInfo info;\n        info.rarityW.assign(M, 1.0);\n        info.uniqBonus.assign(S, 0.0);\n        info.weightedScore.assign(S, 0.0);\n        info.partnerScore.assign(S, 0.0);\n\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> best1(M, -1), best2(M, -1), id1(M, -1);\n\n        for (int l = 0; l < M; l++) {\n            int b1 = -1, b2 = -1, who = -1;\n            for (int i = 0; i < S; i++) {\n                int v = X[i][l];\n                if (v > b1) {\n                    b2 = b1;\n                    b1 = v;\n                    who = i;\n                } else if (v > b2) {\n                    b2 = v;\n                }\n            }\n            best1[l] = b1;\n            best2[l] = max(0, b2);\n            id1[l] = who;\n\n            int gap = best1[l] - best2[l];\n            info.uniqBonus[who] += gap;\n\n            // Rare max coordinates should matter more, but keep weights bounded.\n            info.rarityW[l] = 1.0 + min(2.5, 0.06 * gap);\n        }\n\n        for (int i = 0; i < S; i++) {\n            double ws = 0.0;\n            for (int l = 0; l < M; l++) ws += info.rarityW[l] * X[i][l];\n            info.weightedScore[i] = ws;\n        }\n\n        // Main elite: blend total value + rarity preservation + weighted quality.\n        info.eliteBestV = max_element(V.begin(), V.end()) - V.begin();\n\n        double bestEliteScore = -1e100;\n        info.eliteMain = 0;\n        double uniqCoef = 0.7 + 0.9 * explore;\n        double wcoef = 0.10 + 0.10 * explore;\n        for (int i = 0; i < S; i++) {\n            double sc = V[i] + uniqCoef * info.uniqBonus[i] + wcoef * (info.weightedScore[i] - V[i]);\n            if (sc > bestEliteScore) {\n                bestEliteScore = sc;\n                info.eliteMain = i;\n            }\n        }\n\n        int e = info.eliteMain;\n        double riskCoef = 0.25 + 0.55 * (1.0 - explore);\n\n        for (int i = 0; i < S; i++) {\n            if (i == e) {\n                info.partnerScore[i] = -1e100;\n                continue;\n            }\n            double improve = 0.0, risk = 0.0;\n            for (int l = 0; l < M; l++) {\n                int a = X[i][l];\n                int b = X[e][l];\n                if (a > b) improve += info.rarityW[l] * (a - b);\n                else if (a < b) risk += info.rarityW[l] * (b - a);\n            }\n            info.partnerScore[i] = improve - riskCoef * risk + 0.12 * V[i];\n        }\n\n        return info;\n    }\n\n    vector<int> choose_seeds(int turn, const TurnInfo& info) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        int P = N * N;\n\n        vector<char> used(S, 0);\n        vector<int> selected;\n\n        auto add_force = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Force main elite.\n        add_force(info.eliteMain);\n\n        // Force current best-by-total as well.\n        add_force(info.eliteBestV);\n\n        // Early: keep best seed of each criterion to avoid losing rare max values.\n        if (explore > 0.70) {\n            for (int l = 0; l < M; l++) {\n                int bestId = 0;\n                for (int i = 1; i < S; i++) {\n                    if (X[i][l] > X[bestId][l] ||\n                        (X[i][l] == X[bestId][l] && V[i] > V[bestId])) {\n                        bestId = i;\n                    }\n                }\n                add_force(bestId);\n            }\n        }\n\n        vector<double> candBonus(S, 0.0);\n\n        // Rankings.\n        vector<int> ordV(S), ordW(S), ordP(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        iota(ordW.begin(), ordW.end(), 0);\n        iota(ordP.begin(), ordP.end(), 0);\n\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n        sort(ordW.begin(), ordW.end(), [&](int a, int b) {\n            if (info.weightedScore[a] != info.weightedScore[b]) return info.weightedScore[a] > info.weightedScore[b];\n            return a < b;\n        });\n        sort(ordP.begin(), ordP.end(), [&](int a, int b) {\n            if (info.partnerScore[a] != info.partnerScore[b]) return info.partnerScore[a] > info.partnerScore[b];\n            return a < b;\n        });\n\n        int kTotal = 8 + (int)llround(6 * (1.0 - explore));\n        int kWeighted = 6 + (int)llround(4 * explore);\n        int kPartner = 6 + (int)llround(6 * (1.0 - explore));\n        int kCrit = (explore > 0.55 ? 2 : (explore > 0.20 ? 1 : 0));\n\n        for (int r = 0; r < min(kTotal, S); r++) candBonus[ordV[r]] += 40.0 - 2.0 * r;\n        for (int r = 0; r < min(kWeighted, S); r++) candBonus[ordW[r]] += 24.0 - 2.0 * r;\n        for (int r = 0; r < min(kPartner, S); r++) candBonus[ordP[r]] += 28.0 - 2.0 * r;\n\n        if (info.eliteMain >= 0) candBonus[info.eliteMain] += 40.0;\n        if (info.eliteBestV >= 0) candBonus[info.eliteBestV] += 20.0;\n\n        if (kCrit > 0) {\n            for (int l = 0; l < M; l++) {\n                vector<int> ids(S);\n                iota(ids.begin(), ids.end(), 0);\n                partial_sort(ids.begin(), ids.begin() + min(kCrit, S), ids.end(), [&](int a, int b) {\n                    if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                    return V[a] > V[b];\n                });\n                for (int r = 0; r < kCrit; r++) {\n                    candBonus[ids[r]] += (r == 0 ? 16.0 : 8.0) * info.rarityW[l];\n                }\n            }\n        }\n\n        vector<int> bestSel(M, 0);\n        for (int id : selected) {\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[id][l]);\n        }\n\n        double coverW = 0.65 * explore + 0.20;\n        double partnerW = 0.25 + 0.90 * (1.0 - explore);\n        double weightedExtraW = 0.10 + 0.20 * explore;\n        double uniqW = 0.15 + 0.15 * explore;\n\n        while ((int)selected.size() < P) {\n            double bestScore = -1e100;\n            int bestId = -1;\n\n            for (int i = 0; i < S; i++) if (!used[i]) {\n                double cov = 0.0;\n                for (int l = 0; l < M; l++) {\n                    if (X[i][l] > bestSel[l]) cov += info.rarityW[l] * (X[i][l] - bestSel[l]);\n                }\n\n                double sc =\n                    candBonus[i]\n                    + 1.00 * V[i]\n                    + coverW * cov\n                    + partnerW * max(0.0, info.partnerScore[i])\n                    + weightedExtraW * (info.weightedScore[i] - V[i])\n                    + uniqW * info.uniqBonus[i];\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            used[bestId] = 1;\n            selected.push_back(bestId);\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[bestId][l]);\n        }\n\n        return selected;\n    }\n\n    struct LayoutResult {\n        double score = -1e100;\n        vector<int> layoutGlobal;\n    };\n\n    double compute_pair_base(int ga, int gb, int turn) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        double mu = 0.5 * (V[ga] + V[gb]);\n\n        double sq = 0.0;\n        int diffCnt = 0;\n        int ub = 0;\n        for (int l = 0; l < M; l++) {\n            int d = X[ga][l] - X[gb][l];\n            sq += 1.0 * d * d;\n            if (d != 0) diffCnt++;\n            ub += max(X[ga][l], X[gb][l]);\n        }\n        double sigma = 0.5 * sqrt(sq);\n\n        // Immediate one-child quality approximation.\n        double q = mu + (0.55 + 0.20 * (1.0 - explore)) * sigma;\n\n        // Early turns: upper-bound potential matters more.\n        double gamma = 0.45 * explore;\n        double riskPenalty = (0.45 + 0.35 * (1.0 - explore)) * diffCnt;\n\n        return (1.0 - gamma) * q + gamma * (ub - riskPenalty);\n    }\n\n    double arrangement_score(\n        const vector<int>& perm,                  // position -> local seed\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,    // position adjacency multiplier\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        double sc = 0.0;\n        int P = N * N;\n        for (int p = 0; p < P; p++) {\n            sc += posCoef[p] * nodeVal[perm[p]];\n        }\n        for (auto [u, v] : edgesPos) {\n            sc += multMat[u][v] * pairBase[perm[u]][perm[v]];\n        }\n        return sc;\n    }\n\n    double delta_swap(\n        vector<int>& perm, int p, int q,\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        if (p == q) return 0.0;\n\n        array<pair<int,int>, 8> aff{};\n        int cnt = 0;\n\n        auto add_edge = [&](int a, int b) {\n            if (a > b) swap(a, b);\n            for (int i = 0; i < cnt; i++) {\n                if (aff[i].first == a && aff[i].second == b) return;\n            }\n            aff[cnt++] = {a, b};\n        };\n\n        for (int nb : neighPos[p]) add_edge(p, nb);\n        for (int nb : neighPos[q]) add_edge(q, nb);\n\n        double oldv = 0.0, newv = 0.0;\n\n        oldv += posCoef[p] * nodeVal[perm[p]] + posCoef[q] * nodeVal[perm[q]];\n        newv += posCoef[p] * nodeVal[perm[q]] + posCoef[q] * nodeVal[perm[p]];\n\n        auto get_seed_after = [&](int pos) -> int {\n            if (pos == p) return perm[q];\n            if (pos == q) return perm[p];\n            return perm[pos];\n        };\n\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            oldv += multMat[a][b] * pairBase[perm[a]][perm[b]];\n            newv += multMat[a][b] * pairBase[get_seed_after(a)][get_seed_after(b)];\n        }\n\n        return newv - oldv;\n    }\n\n    LayoutResult optimize_layout(const vector<int>& selected, const TurnInfo& info, int turn) {\n        int P = N * N;\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> localToGlobal = selected;\n        vector<int> globalToLocal(S, -1);\n        for (int i = 0; i < P; i++) globalToLocal[localToGlobal[i]] = i;\n\n        vector<vector<double>> pairBase(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                double w = compute_pair_base(localToGlobal[i], localToGlobal[j], turn);\n                pairBase[i][j] = pairBase[j][i] = w;\n            }\n        }\n\n        vector<double> nodeVal(P, 0.0);\n        for (int i = 0; i < P; i++) {\n            int g = localToGlobal[i];\n            nodeVal[i] =\n                0.12 * V[g]\n                + 0.18 * max(0.0, info.partnerScore[g])\n                + 0.08 * info.uniqBonus[g]\n                + 0.04 * (info.weightedScore[g] - V[g]);\n        }\n\n        vector<int> posCoef(P, 0);\n        for (int p = 0; p < P; p++) {\n            posCoef[p] = (int)neighPos[p].size() - 2; // corner 0, border 1, interior 2\n        }\n\n        vector<int> eliteCandidates;\n        if (globalToLocal[info.eliteMain] != -1) eliteCandidates.push_back(info.eliteMain);\n        if (info.eliteBestV != info.eliteMain && globalToLocal[info.eliteBestV] != -1) {\n            eliteCandidates.push_back(info.eliteBestV);\n        }\n        if (eliteCandidates.empty()) eliteCandidates.push_back(localToGlobal[0]);\n\n        LayoutResult best;\n\n        for (int eliteGlobal : eliteCandidates) {\n            int eliteLocal = globalToLocal[eliteGlobal];\n            if (eliteLocal < 0) continue;\n\n            for (int hubPos : centers) {\n                double hubBoost = 0.55 + 0.55 * (1.0 - explore);\n\n                vector<vector<double>> multMat(P, vector<double>(P, 0.0));\n                for (auto [u, v] : edgesPos) {\n                    double mul = 1.0 + ((u == hubPos || v == hubPos) ? hubBoost : 0.0);\n                    multMat[u][v] = multMat[v][u] = mul;\n                }\n\n                vector<int> perm(P, -1);\n                vector<char> usedLocal(P, 0);\n\n                perm[hubPos] = eliteLocal;\n                usedLocal[eliteLocal] = 1;\n\n                // Put good elite partners around the hub first.\n                vector<int> around = neighPos[hubPos];\n                vector<int> remSeeds;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) remSeeds.push_back(i);\n\n                sort(remSeeds.begin(), remSeeds.end(), [&](int a, int b) {\n                    int ga = localToGlobal[a], gb = localToGlobal[b];\n                    double sa =\n                        0.75 * max(0.0, info.partnerScore[ga]) +\n                        0.40 * V[ga] +\n                        0.10 * info.weightedScore[ga];\n                    double sb =\n                        0.75 * max(0.0, info.partnerScore[gb]) +\n                        0.40 * V[gb] +\n                        0.10 * info.weightedScore[gb];\n                    if (sa != sb) return sa > sb;\n                    return ga < gb;\n                });\n\n                int ptr = 0;\n                for (int p : around) {\n                    while (ptr < (int)remSeeds.size() && usedLocal[remSeeds[ptr]]) ptr++;\n                    if (ptr < (int)remSeeds.size()) {\n                        perm[p] = remSeeds[ptr];\n                        usedLocal[remSeeds[ptr]] = 1;\n                        ptr++;\n                    }\n                }\n\n                // Fill remaining positions by general node score.\n                vector<int> posFill;\n                for (int p : posOrder) {\n                    if (perm[p] == -1) posFill.push_back(p);\n                }\n\n                vector<int> seedFill;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) seedFill.push_back(i);\n\n                sort(seedFill.begin(), seedFill.end(), [&](int a, int b) {\n                    if (nodeVal[a] != nodeVal[b]) return nodeVal[a] > nodeVal[b];\n                    return localToGlobal[a] < localToGlobal[b];\n                });\n\n                for (int k = 0; k < (int)posFill.size(); k++) {\n                    perm[posFill[k]] = seedFill[k];\n                }\n\n                double cur = arrangement_score(perm, pairBase, multMat, nodeVal, posCoef);\n\n                // SA / hill-climb with elite fixed at hub.\n                vector<char> fixed(P, 0);\n                fixed[hubPos] = 1;\n\n                int ITER = 9000;\n                double T0 = 18.0;\n                double T1 = 0.15;\n\n                for (int it = 0; it < ITER; it++) {\n                    int p = rng.next_int(P);\n                    int q = rng.next_int(P);\n                    if (p == q || fixed[p] || fixed[q]) continue;\n\n                    double temp = T0 * pow(T1 / T0, (double)it / ITER);\n                    double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n\n                    if (d >= 0.0 || rng.next_double() < exp(d / temp)) {\n                        swap(perm[p], perm[q]);\n                        cur += d;\n                    }\n                }\n\n                // Final hill-climb.\n                for (int rep = 0; rep < 12; rep++) {\n                    double bestDelta = 1e-12;\n                    int bp = -1, bq = -1;\n                    for (int p = 0; p < P; p++) if (!fixed[p]) {\n                        for (int q = p + 1; q < P; q++) if (!fixed[q]) {\n                            double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n                            if (d > bestDelta) {\n                                bestDelta = d;\n                                bp = p;\n                                bq = q;\n                            }\n                        }\n                    }\n                    if (bp == -1) break;\n                    swap(perm[bp], perm[bq]);\n                    cur += bestDelta;\n                }\n\n                if (cur > best.score) {\n                    best.score = cur;\n                    best.layoutGlobal.assign(P, -1);\n                    for (int p = 0; p < P; p++) {\n                        best.layoutGlobal[p] = localToGlobal[perm[p]];\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> T;\n        S = 2 * N * (N - 1);\n\n        build_grid();\n        if (!read_seed_set()) return;\n\n        for (int turn = 0; turn < T; turn++) {\n            V.assign(S, 0);\n            for (int i = 0; i < S; i++) {\n                for (int l = 0; l < M; l++) V[i] += X[i][l];\n            }\n\n            TurnInfo info = analyze_turn(turn);\n            vector<int> selected = choose_seeds(turn, info);\n            LayoutResult res = optimize_layout(selected, info, turn);\n            vector<int> layout = res.layoutGlobal;\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    if (c) cout << ' ';\n                    cout << layout[r * N + c];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (!read_seed_set()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\nstatic inline bool operator==(const Pt& a, const Pt& b) {\n    return a.x == b.x && a.y == b.y;\n}\n\nstatic const int DX[4] = {0, 1, 0, -1}; // R, D, L, U\nstatic const int DY[4] = {1, 0, -1, 0};\n\nstruct Goal {\n    bool ok = false;\n    int leaf = -1;\n    int dir = -1;\n    Pt rootPos{-1, -1};\n    Pt cell{-1, -1};\n    int cost = INT_MAX;\n    int md = INT_MAX;\n    int rd = INT_MAX;\n};\n\nstruct Problem {\n    int N, M, Vmax;\n    vector<string> s, t;\n\n    vector<Pt> surplusCells, deficitCells;\n    vector<vector<int>> sid, did;\n\n    Pt clamp(Pt p) const {\n        p.x = max(0, min(N - 1, p.x));\n        p.y = max(0, min(N - 1, p.y));\n        return p;\n    }\n\n    Pt centroid(const vector<Pt>& v) const {\n        if (v.empty()) return {N / 2, N / 2};\n        long long sx = 0, sy = 0;\n        for (auto &p : v) sx += p.x, sy += p.y;\n        return clamp({(int)llround((double)sx / (int)v.size()),\n                      (int)llround((double)sy / (int)v.size())});\n    }\n\n    Pt medianAll() const {\n        vector<int> xs, ys;\n        xs.reserve(surplusCells.size() + deficitCells.size());\n        ys.reserve(surplusCells.size() + deficitCells.size());\n        for (auto &p : surplusCells) xs.push_back(p.x), ys.push_back(p.y);\n        for (auto &p : deficitCells) xs.push_back(p.x), ys.push_back(p.y);\n        if (xs.empty()) return {N / 2, N / 2};\n        nth_element(xs.begin(), xs.begin() + xs.size() / 2, xs.end());\n        nth_element(ys.begin(), ys.begin() + ys.size() / 2, ys.end());\n        return clamp({xs[xs.size() / 2], ys[ys.size() / 2]});\n    }\n\n    Pt centroidAll() const {\n        vector<Pt> all = surplusCells;\n        all.insert(all.end(), deficitCells.begin(), deficitCells.end());\n        return centroid(all);\n    }\n\n    Pt center() const {\n        return {N / 2, N / 2};\n    }\n\n    Pt centroidSurplus() const {\n        return centroid(surplusCells);\n    }\n\n    Pt centroidDeficit() const {\n        return centroid(deficitCells);\n    }\n\n    Pt midpointSD() const {\n        Pt a = centroidSurplus();\n        Pt b = centroidDeficit();\n        return clamp({(a.x + b.x) / 2, (a.y + b.y) / 2});\n    }\n};\n\nstruct SimResult {\n    bool complete = false;\n    int turns = (int)1e9;\n    Pt initialRoot{0, 0};\n    vector<int> len;\n    vector<string> ops;\n};\n\nstruct Simulator {\n    const Problem& P;\n\n    int N, K, Vp;\n    vector<int> len;\n\n    Pt initialRoot, root;\n    vector<int> dirLeaf;\n    vector<char> holding;\n    int holdCnt = 0;\n\n    vector<char> aliveS, aliveD;\n    int remS = 0, remD = 0;\n\n    vector<string> ops;\n    int cutoffTurns;\n\n    Simulator(const Problem& prob, const vector<int>& lengths, Pt rootInit, int cutoff)\n        : P(prob), N(prob.N), K((int)lengths.size() - 1), Vp((int)lengths.size()),\n          len(lengths), initialRoot(rootInit), root(rootInit), cutoffTurns(cutoff)\n    {\n        dirLeaf.assign(Vp, 0);\n        holding.assign(Vp, false);\n        aliveS.assign(P.surplusCells.size(), true);\n        aliveD.assign(P.deficitCells.size(), true);\n        remS = (int)P.surplusCells.size();\n        remD = (int)P.deficitCells.size();\n    }\n\n    inline bool inb(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    inline int rotDist(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        return min(d, 4 - d);\n    }\n\n    inline int applyRot(int cur, char c) const {\n        if (c == 'L') return (cur + 3) & 3;\n        if (c == 'R') return (cur + 1) & 3;\n        return cur;\n    }\n\n    inline char oneStepRotToward(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'L';\n    }\n\n    inline Pt moveRoot(Pt p, char mv) const {\n        if (mv == 'U') p.x--;\n        else if (mv == 'D') p.x++;\n        else if (mv == 'L') p.y--;\n        else if (mv == 'R') p.y++;\n        return p;\n    }\n\n    inline bool isSurplusCell(int x, int y) const {\n        int id = P.sid[x][y];\n        return (id != -1 && aliveS[id]);\n    }\n\n    inline bool isDeficitCell(int x, int y) const {\n        int id = P.did[x][y];\n        return (id != -1 && aliveD[id]);\n    }\n\n    pair<bool, Pt> remainingCentroid(bool deficit) const {\n        long long sx = 0, sy = 0;\n        int cnt = 0;\n        if (deficit) {\n            for (int i = 0; i < (int)P.deficitCells.size(); i++) if (aliveD[i]) {\n                sx += P.deficitCells[i].x;\n                sy += P.deficitCells[i].y;\n                cnt++;\n            }\n        } else {\n            for (int i = 0; i < (int)P.surplusCells.size(); i++) if (aliveS[i]) {\n                sx += P.surplusCells[i].x;\n                sy += P.surplusCells[i].y;\n                cnt++;\n            }\n        }\n        if (cnt == 0) return {false, {0, 0}};\n        return {true, {(int)llround((double)sx / cnt), (int)llround((double)sy / cnt)}};\n    }\n\n    Goal findGoal(bool wantDrop) const {\n        Goal best;\n        if (wantDrop) {\n            if (holdCnt == 0 || remD == 0) return best;\n            for (int id = 0; id < (int)P.deficitCells.size(); id++) {\n                if (!aliveD[id]) continue;\n                const Pt& c = P.deficitCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (!holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        } else {\n            if (holdCnt == K || remS == 0) return best;\n            for (int id = 0; id < (int)P.surplusCells.size(); id++) {\n                if (!aliveS[id]) continue;\n                const Pt& c = P.surplusCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        }\n        return best;\n    }\n\n    bool chooseMode(const Goal& gp, const Goal& gd) const {\n        if (remD == 0 && holdCnt > 0) return true;\n        if (holdCnt == 0) return false;\n        if (holdCnt == K) return true;\n        if (!gd.ok) return false;\n        if (!gp.ok) return true;\n\n        if (holdCnt * 2 < K) {\n            if (gd.cost + 2 < gp.cost) return true;\n            return false;\n        } else {\n            if (gp.cost + 2 < gd.cost) return false;\n            return true;\n        }\n    }\n\n    struct MatchResult {\n        int cnt = 0;\n        int priSum = 0;\n        vector<char> rot;\n        vector<char> act;\n        MatchResult() {}\n        MatchResult(int Vp): rot(Vp, '.'), act(Vp, '.') {}\n    };\n\n    struct EdgeCand {\n        int leaf;\n        int cellIdx;\n        char rot;\n        int ndir;\n        int pri;\n    };\n\n    struct MCMFEdge {\n        int to, rev, cap, cost;\n    };\n\n    void add_edge(vector<vector<MCMFEdge>>& g, int fr, int to, int cap, int cost) const {\n        g[fr].push_back(MCMFEdge{to, (int)g[to].size(), cap, cost});\n        g[to].push_back(MCMFEdge{fr, (int)g[fr].size() - 1, 0, -cost});\n    }\n\n    MatchResult buildMatching(Pt newRoot, bool wantDrop, const Goal* prefGoal) const {\n        MatchResult res(Vp);\n\n        vector<Pt> cells;\n        vector<EdgeCand> cands;\n        vector<vector<int>> candIdxByLeaf(Vp);\n\n        auto getCellIdx = [&](int x, int y) {\n            for (int i = 0; i < (int)cells.size(); i++) {\n                if (cells[i].x == x && cells[i].y == y) return i;\n            }\n            cells.push_back({x, y});\n            return (int)cells.size() - 1;\n        };\n\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (wantDrop && !holding[leaf]) continue;\n            if (!wantDrop && holding[leaf]) continue;\n\n            vector<pair<int, EdgeCand>> tmp;\n            for (auto [rc, delta] : vector<pair<char,int>>{{'.',0},{'L',-1},{'R',+1}}) {\n                int nd = dirLeaf[leaf];\n                if (delta == -1) nd = (nd + 3) & 3;\n                else if (delta == +1) nd = (nd + 1) & 3;\n\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                if (!inb(x, y)) continue;\n\n                bool ok = wantDrop ? isDeficitCell(x, y) : isSurplusCell(x, y);\n                if (!ok) continue;\n\n                int pri = 0;\n                if (prefGoal && prefGoal->ok &&\n                    prefGoal->leaf == leaf &&\n                    prefGoal->dir == nd &&\n                    prefGoal->rootPos == newRoot &&\n                    prefGoal->cell.x == x && prefGoal->cell.y == y) {\n                    pri += 100;\n                }\n                pri += (rc == '.' ? 2 : 1);\n\n                int ci = getCellIdx(x, y);\n                EdgeCand e{leaf, ci, rc, nd, pri};\n\n                bool found = false;\n                for (auto &pe : tmp) {\n                    if (pe.first == ci) {\n                        if (e.pri > pe.second.pri) pe.second = e;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) tmp.push_back({ci, e});\n            }\n\n            for (auto &pe : tmp) {\n                int idx = (int)cands.size();\n                cands.push_back(pe.second);\n                candIdxByLeaf[leaf].push_back(idx);\n            }\n        }\n\n        if (cands.empty()) return res;\n\n        vector<int> usedLeafs;\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (!candIdxByLeaf[leaf].empty()) usedLeafs.push_back(leaf);\n        }\n\n        int L = (int)usedLeafs.size();\n        int C = (int)cells.size();\n\n        vector<int> leafNode(Vp, -1);\n        for (int i = 0; i < L; i++) leafNode[usedLeafs[i]] = 1 + i;\n        int cellBase = 1 + L;\n        int SRC = 0;\n        int SNK = cellBase + C;\n        int V = SNK + 1;\n\n        vector<vector<MCMFEdge>> g(V);\n\n        for (int leaf : usedLeafs) add_edge(g, SRC, leafNode[leaf], 1, 0);\n        for (int ci = 0; ci < C; ci++) add_edge(g, cellBase + ci, SNK, 1, 0);\n\n        const int BASE = 10000;\n        struct Ref {\n            int leaf;\n            int edgePos;\n            int pri;\n            char rot;\n        };\n        vector<Ref> refs;\n\n        for (int idx = 0; idx < (int)cands.size(); idx++) {\n            auto &e = cands[idx];\n            int u = leafNode[e.leaf];\n            int v = cellBase + e.cellIdx;\n            int pos = (int)g[u].size();\n            add_edge(g, u, v, 1, -(BASE + e.pri));\n            refs.push_back({e.leaf, pos, e.pri, e.rot});\n        }\n\n        while (true) {\n            const int INF = 1e9;\n            vector<int> dist(V, INF), pv(V, -1), pe(V, -1);\n            vector<char> inq(V, false);\n            queue<int> q;\n            dist[SRC] = 0;\n            q.push(SRC);\n            inq[SRC] = true;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                inq[v] = false;\n                for (int i = 0; i < (int)g[v].size(); i++) {\n                    auto &e = g[v][i];\n                    if (e.cap <= 0) continue;\n                    int nd = dist[v] + e.cost;\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        if (!inq[e.to]) {\n                            inq[e.to] = true;\n                            q.push(e.to);\n                        }\n                    }\n                }\n            }\n\n            if (dist[SNK] == INF || dist[SNK] >= 0) break;\n\n            int v = SNK;\n            while (v != SRC) {\n                auto &e = g[pv[v]][pe[v]];\n                e.cap -= 1;\n                g[v][e.rev].cap += 1;\n                v = pv[v];\n            }\n        }\n\n        for (auto &r : refs) {\n            auto &e = g[leafNode[r.leaf]][r.edgePos];\n            if (e.cap == 0) {\n                res.cnt++;\n                res.priSum += r.pri;\n                res.rot[r.leaf] = r.rot;\n                res.act[r.leaf] = 'P';\n            }\n        }\n        return res;\n    }\n\n    long long evaluateMove(\n        char mv,\n        const Goal& gp,\n        const Goal& gd,\n        bool preferDrop,\n        bool hasCD, Pt cenD,\n        bool hasCS, Pt cenS,\n        MatchResult* outDrop,\n        MatchResult* outPick\n    ) const {\n        Pt nr = moveRoot(root, mv);\n        MatchResult dropRes = buildMatching(nr, true, preferDrop ? &gd : nullptr);\n        MatchResult pickRes = buildMatching(nr, false, preferDrop ? nullptr : &gp);\n\n        int primaryCnt = preferDrop ? dropRes.cnt : pickRes.cnt;\n        int secondaryCnt = preferDrop ? pickRes.cnt : dropRes.cnt;\n        int primaryPri = preferDrop ? dropRes.priSum : pickRes.priSum;\n        int secondaryPri = preferDrop ? pickRes.priSum : dropRes.priSum;\n\n        const Goal& mainGoal = preferDrop ? gd : gp;\n        const Goal& subGoal  = preferDrop ? gp : gd;\n\n        long long score = 0;\n        score += 1LL * primaryCnt * 1000000;\n        score += 1LL * secondaryCnt * 20000;\n        score += 1LL * primaryPri * 200;\n        score += 1LL * secondaryPri * 20;\n\n        if (mainGoal.ok) {\n            int d = abs(nr.x - mainGoal.rootPos.x) + abs(nr.y - mainGoal.rootPos.y);\n            score -= 100LL * d;\n        } else if (subGoal.ok) {\n            int d = abs(nr.x - subGoal.rootPos.x) + abs(nr.y - subGoal.rootPos.y);\n            score -= 100LL * d;\n        }\n\n        // Very mild global guidance only when nothing immediate happens.\n        if (primaryCnt + secondaryCnt == 0) {\n            if (preferDrop && hasCD) {\n                score -= 8LL * (abs(nr.x - cenD.x) + abs(nr.y - cenD.y));\n            } else if (!preferDrop && hasCS) {\n                score -= 8LL * (abs(nr.x - cenS.x) + abs(nr.y - cenS.y));\n            }\n        }\n\n        if (mv == '.' && (primaryCnt + secondaryCnt) > 0) score += 5;\n\n        if (outDrop) *outDrop = std::move(dropRes);\n        if (outPick) *outPick = std::move(pickRes);\n        return score;\n    }\n\n    void appendCommand(char mv, const vector<char>& rot, const vector<char>& act) {\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        for (int i = 1; i <= K; i++) {\n            cmd[i] = rot[i];\n            cmd[Vp + i] = act[i];\n        }\n        ops.push_back(cmd);\n    }\n\n    char chooseSimpleMoveToward(Pt goalPos) const {\n        int dx = goalPos.x - root.x;\n        int dy = goalPos.y - root.y;\n        if (abs(dx) >= abs(dy)) {\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n        } else {\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n        }\n        return '.';\n    }\n\n    bool actOneGoal(const Goal& g, bool wantDrop) {\n        int leaf = g.leaf;\n        while (true) {\n            if ((int)ops.size() >= 100000 || (int)ops.size() >= cutoffTurns) return false;\n\n            char mv = chooseSimpleMoveToward(g.rootPos);\n            char rc = oneStepRotToward(dirLeaf[leaf], g.dir);\n\n            Pt nr = moveRoot(root, mv);\n            int nd = applyRot(dirLeaf[leaf], rc);\n            bool canAct = (nr == g.rootPos && nd == g.dir);\n\n            vector<char> rot(Vp, '.');\n            vector<char> act(Vp, '.');\n            rot[leaf] = rc;\n            if (canAct) act[leaf] = 'P';\n\n            appendCommand(mv, rot, act);\n\n            root = nr;\n            dirLeaf[leaf] = nd;\n\n            if (canAct) {\n                if (wantDrop) {\n                    int id = P.did[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveD[id] && holding[leaf]) {\n                        aliveD[id] = false;\n                        remD--;\n                        holding[leaf] = false;\n                        holdCnt--;\n                        return true;\n                    }\n                } else {\n                    int id = P.sid[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveS[id] && !holding[leaf]) {\n                        aliveS[id] = false;\n                        remS--;\n                        holding[leaf] = true;\n                        holdCnt++;\n                        return true;\n                    }\n                }\n                return false;\n            }\n        }\n    }\n\n    void steerIdleLeaves(\n        Pt newRoot,\n        vector<char>& rot,\n        vector<char>& act,\n        bool hasCD, Pt cenD,\n        bool hasCS, Pt cenS\n    ) const {\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (act[leaf] != '.') continue;\n            if (rot[leaf] != '.') continue;\n\n            bool wantDrop = holding[leaf];\n            if (wantDrop && !hasCD) continue;\n            if (!wantDrop && !hasCS) continue;\n            Pt target = wantDrop ? cenD : cenS;\n\n            int cur = dirLeaf[leaf];\n            vector<pair<char,int>> opts = {{'.', cur}, {'L', (cur + 3) & 3}, {'R', (cur + 1) & 3}};\n\n            int bestVal = INT_MAX;\n            char bestRot = '.';\n            for (auto [rc, nd] : opts) {\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                int val = abs(x - target.x) + abs(y - target.y);\n                if (rc != '.') val += 1; // tiny penalty to avoid useless flapping\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestRot = rc;\n                }\n            }\n            rot[leaf] = bestRot;\n        }\n    }\n\n    SimResult run() {\n        while ((remD > 0 || holdCnt > 0) &&\n               (int)ops.size() < 100000 &&\n               (int)ops.size() < cutoffTurns)\n        {\n            int noActionStreak = 0;\n            bool progressedInGreedyPhase = false;\n\n            // Greedy multi-action phase\n            while ((remD > 0 || holdCnt > 0) &&\n                   (int)ops.size() < 100000 &&\n                   (int)ops.size() < cutoffTurns)\n            {\n                Goal gp = findGoal(false);\n                Goal gd = findGoal(true);\n                if (!gp.ok && !gd.ok) break;\n\n                bool preferDrop = chooseMode(gp, gd);\n                auto [hasCD, cenD] = remainingCentroid(true);\n                auto [hasCS, cenS] = remainingCentroid(false);\n\n                vector<char> legalMoves = {'.', 'U', 'D', 'L', 'R'};\n                long long bestScore = LLONG_MIN;\n                char bestMv = '.';\n                MatchResult bestDrop(Vp), bestPick(Vp);\n\n                for (char mv : legalMoves) {\n                    Pt nr = moveRoot(root, mv);\n                    if (!inb(nr.x, nr.y)) continue;\n\n                    MatchResult dr(Vp), pr(Vp);\n                    long long sc = evaluateMove(mv, gp, gd, preferDrop, hasCD, cenD, hasCS, cenS, &dr, &pr);\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestMv = mv;\n                        bestDrop = std::move(dr);\n                        bestPick = std::move(pr);\n                    }\n                }\n\n                Pt newRoot = moveRoot(root, bestMv);\n                vector<char> rot(Vp, '.');\n                vector<char> act(Vp, '.');\n\n                // drops first\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (bestDrop.act[leaf] == 'P') {\n                        rot[leaf] = bestDrop.rot[leaf];\n                        act[leaf] = 'P';\n                    }\n                }\n                // picks second on unused leaves\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (act[leaf] == '.' && bestPick.act[leaf] == 'P') {\n                        rot[leaf] = bestPick.rot[leaf];\n                        act[leaf] = 'P';\n                    }\n                }\n\n                const Goal& mainGoal = preferDrop ? gd : gp;\n                if (mainGoal.ok && act[mainGoal.leaf] == '.') {\n                    rot[mainGoal.leaf] = oneStepRotToward(dirLeaf[mainGoal.leaf], mainGoal.dir);\n                }\n\n                // Pre-rotate idle leaves toward remaining mass\n                steerIdleLeaves(newRoot, rot, act, hasCD, cenD, hasCS, cenS);\n\n                appendCommand(bestMv, rot, act);\n\n                bool didAction = false;\n                root = newRoot;\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    dirLeaf[leaf] = applyRot(dirLeaf[leaf], rot[leaf]);\n                }\n\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (act[leaf] != 'P') continue;\n                    int x = root.x + DX[dirLeaf[leaf]] * len[leaf];\n                    int y = root.y + DY[dirLeaf[leaf]] * len[leaf];\n                    if (!inb(x, y)) continue;\n\n                    if (holding[leaf]) {\n                        int id = P.did[x][y];\n                        if (id != -1 && aliveD[id]) {\n                            aliveD[id] = false;\n                            remD--;\n                            holding[leaf] = false;\n                            holdCnt--;\n                            didAction = true;\n                        }\n                    } else {\n                        int id = P.sid[x][y];\n                        if (id != -1 && aliveS[id]) {\n                            aliveS[id] = false;\n                            remS--;\n                            holding[leaf] = true;\n                            holdCnt++;\n                            didAction = true;\n                        }\n                    }\n                }\n\n                if (didAction) {\n                    noActionStreak = 0;\n                    progressedInGreedyPhase = true;\n                } else {\n                    noActionStreak++;\n                }\n\n                if (noActionStreak > 5 * N + 60) break;\n            }\n\n            if (remD == 0 && holdCnt == 0) break;\n            if ((int)ops.size() >= 100000 || (int)ops.size() >= cutoffTurns) break;\n\n            // Deadlock breaker: do one deterministic action, then return to greedy.\n            Goal gp = findGoal(false);\n            Goal gd = findGoal(true);\n            if (!gp.ok && !gd.ok) break;\n\n            bool wantDrop = chooseMode(gp, gd);\n            Goal g = wantDrop ? gd : gp;\n            if (!g.ok) {\n                wantDrop = !wantDrop;\n                g = wantDrop ? gd : gp;\n            }\n            if (!g.ok) break;\n\n            bool ok = actOneGoal(g, wantDrop);\n            if (!ok) {\n                // If deterministic break also fails, stop.\n                break;\n            }\n\n            (void)progressedInGreedyPhase;\n        }\n\n        SimResult res;\n        res.initialRoot = initialRoot;\n        res.len = len;\n        res.ops = ops;\n        res.complete = (remD == 0 && holdCnt == 0);\n        res.turns = res.complete ? (int)ops.size() : (int)1e9;\n        return res;\n    }\n};\n\nstatic vector<vector<int>> generateDesigns(int K, int N) {\n    vector<vector<int>> designs;\n    auto add = [&](vector<int> a) {\n        if ((int)a.size() != K + 1) return;\n        for (int i = 1; i <= K; i++) a[i] = max(1, min(N - 1, a[i]));\n        for (auto &b : designs) if (b == a) return;\n        designs.push_back(a);\n    };\n\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 2);\n        a[0] = 0;\n        add(a);\n    }\n    {\n        int R = max(1, min(3, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        int R = max(1, min(4, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        int R = max(1, min(5, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) / 2;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = i;\n        add(a);\n    }\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        if (K >= 1) a[K] = min(N - 1, 2);\n        if (K >= 2) a[K - 1] = min(N - 1, 3);\n        if (K >= 3) a[K - 2] = min(N - 1, 4);\n        if (K >= 4) a[K - 3] = min(N - 1, 5);\n        add(a);\n    }\n\n    return designs;\n}\n\nstatic vector<Pt> generateRoots(const Problem& P) {\n    vector<Pt> roots;\n    auto add = [&](Pt p) {\n        p = P.clamp(p);\n        for (auto &q : roots) if (q == p) return;\n        roots.push_back(p);\n    };\n\n    add(P.medianAll());\n    add(P.centroidAll());\n    add(P.center());\n    add(P.centroidSurplus());\n    add(P.centroidDeficit());\n    add(P.midpointSD());\n\n    return roots;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem P;\n    cin >> P.N >> P.M >> P.Vmax;\n    P.s.resize(P.N);\n    P.t.resize(P.N);\n    for (int i = 0; i < P.N; i++) cin >> P.s[i];\n    for (int i = 0; i < P.N; i++) cin >> P.t[i];\n\n    P.sid.assign(P.N, vector<int>(P.N, -1));\n    P.did.assign(P.N, vector<int>(P.N, -1));\n\n    for (int i = 0; i < P.N; i++) {\n        for (int j = 0; j < P.N; j++) {\n            if (P.s[i][j] == '1' && P.t[i][j] == '0') {\n                P.sid[i][j] = (int)P.surplusCells.size();\n                P.surplusCells.push_back({i, j});\n            }\n            if (P.s[i][j] == '0' && P.t[i][j] == '1') {\n                P.did[i][j] = (int)P.deficitCells.size();\n                P.deficitCells.push_back({i, j});\n            }\n        }\n    }\n\n    int K = P.Vmax - 1;\n    auto designs = generateDesigns(K, P.N);\n    auto roots = generateRoots(P);\n\n    SimResult best;\n    int cutoff = 1000000000;\n\n    for (const auto& root : roots) {\n        for (const auto& len : designs) {\n            Simulator sim(P, len, root, cutoff);\n            SimResult cur = sim.run();\n            if (cur.complete && cur.turns < best.turns) {\n                best = std::move(cur);\n                cutoff = best.turns;\n            }\n        }\n    }\n\n    if (!best.complete) {\n        Simulator sim(P, designs[0], roots[0], 1000000000);\n        best = sim.run();\n    }\n\n    int Vp = K + 1;\n    cout << Vp << '\\n';\n    for (int i = 1; i <= K; i++) {\n        cout << 0 << ' ' << best.len[i] << '\\n';\n    }\n    cout << best.initialRoot.x << ' ' << best.initialRoot.y << '\\n';\n    for (const string& cmd : best.ops) {\n        cout << cmd << '\\n';\n    }\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Point {\n    int x, y;\n};\n\nstruct WPoint {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Candidate {\n    vector<Point> poly;\n    int approx = INT_MIN / 4;\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    bool over(double limit_ms) const {\n        return elapsed_ms() > limit_ms;\n    }\n};\n\nstatic inline uint64_t pack_xy(int x, int y) {\n    return (uint64_t(uint32_t(x)) << 32) | uint32_t(y);\n}\n\nstatic inline bool on_segment(const Point& p, const Point& a, const Point& b) {\n    if (a.x == b.x) {\n        if (p.x != a.x) return false;\n        return min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);\n    } else if (a.y == b.y) {\n        if (p.y != a.y) return false;\n        return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x);\n    }\n    return false;\n}\n\nstatic bool inside_polygon_inclusive(const Point& p, const vector<Point>& poly) {\n    bool in = false;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        Point a = poly[i];\n        Point b = poly[(i + 1) % n];\n\n        if (on_segment(p, a, b)) return true;\n\n        // ray cast to +x direction; only vertical edges matter\n        if (a.x == b.x) {\n            if (a.y > b.y) swap(a, b);\n            if (a.y <= p.y && p.y < b.y && p.x < a.x) {\n                in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int exact_diff(const vector<Point>& poly, const vector<WPoint>& pts) {\n    if (poly.empty()) return INT_MIN / 4;\n\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    for (auto &q : poly) {\n        minx = min(minx, q.x);\n        maxx = max(maxx, q.x);\n        miny = min(miny, q.y);\n        maxy = max(maxy, q.y);\n    }\n\n    int diff = 0;\n    for (auto &pt : pts) {\n        if (pt.x < minx || pt.x > maxx || pt.y < miny || pt.y > maxy) continue;\n        if (inside_polygon_inclusive(Point{pt.x, pt.y}, poly)) diff += pt.w;\n    }\n    return diff;\n}\n\nstatic long long polygon_perimeter(const vector<Point>& poly) {\n    long long per = 0;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % n];\n        per += llabs((long long)a.x - b.x) + llabs((long long)a.y - b.y);\n    }\n    return per;\n}\n\nstatic bool legal_polygon(const vector<Point>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    if (polygon_perimeter(poly) > 400000LL) return false;\n    set<pair<int,int>> st;\n    for (auto &p : poly) {\n        if (p.x < 0 || p.x > 100000 || p.y < 0 || p.y > 100000) return false;\n        if (!st.insert({p.x, p.y}).second) return false;\n    }\n    return true;\n}\n\nstatic vector<Point> fallback_polygon(const unordered_set<uint64_t>& occ) {\n    for (int x = 0; x <= 200; x++) {\n        for (int y = 0; y <= 200; y++) {\n            if (!occ.count(pack_xy(x, y)) &&\n                !occ.count(pack_xy(x + 1, y)) &&\n                !occ.count(pack_xy(x, y + 1)) &&\n                !occ.count(pack_xy(x + 1, y + 1))) {\n                return {\n                    {x, y},\n                    {x + 1, y},\n                    {x + 1, y + 1},\n                    {x, y + 1}\n                };\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nstatic vector<int> build_lines(int S, int offset) {\n    vector<int> v;\n    v.push_back(0);\n    for (int x = offset; x < 100000; x += S) {\n        if (x > 0) v.push_back(x);\n    }\n    if (v.back() != 100000) v.push_back(100000);\n    sort(v.begin(), v.end());\n    v.erase(unique(v.begin(), v.end()), v.end());\n    return v;\n}\n\nstatic int find_cell(const vector<int>& lines, int coord) {\n    int idx = int(upper_bound(lines.begin(), lines.end(), coord) - lines.begin()) - 1;\n    if (idx < 0) idx = 0;\n    if (idx >= (int)lines.size() - 1) idx = (int)lines.size() - 2;\n    return idx;\n}\n\nstatic vector<char> solve_selection_by_cut(const vector<int>& cell_w, int W, int H, int lambda) {\n    if (lambda == 0) {\n        vector<char> sel(W * H, 0);\n        for (int i = 0; i < W * H; i++) {\n            if (cell_w[i] > 0) sel[i] = 1;\n        }\n        return sel;\n    }\n\n    int SRC = W * H;\n    int SNK = W * H + 1;\n    mf_graph<int> g(W * H + 2);\n\n    auto id = [&](int x, int y) -> int {\n        return y * W + x;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int outside_sides = 0;\n            if (x == 0) outside_sides++;\n            if (x == W - 1) outside_sides++;\n            if (y == 0) outside_sides++;\n            if (y == H - 1) outside_sides++;\n\n            int u = cell_w[v] - lambda * outside_sides;\n            if (u >= 0) g.add_edge(SRC, v, u);\n            else g.add_edge(v, SNK, -u);\n\n            if (x + 1 < W) {\n                int to = id(x + 1, y);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n            if (y + 1 < H) {\n                int to = id(x, y + 1);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n        }\n    }\n\n    g.flow(SRC, SNK);\n    auto cut = g.min_cut(SRC);\n\n    vector<char> sel(W * H, 0);\n    for (int i = 0; i < W * H; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nstatic void fill_holes(vector<char>& sel, int W, int H) {\n    vector<char> vis(W * H, 0);\n    queue<int> q;\n\n    auto push_if = [&](int x, int y) {\n        int id = y * W + x;\n        if (!sel[id] && !vis[id]) {\n            vis[id] = 1;\n            q.push(id);\n        }\n    };\n\n    for (int x = 0; x < W; x++) {\n        push_if(x, 0);\n        push_if(x, H - 1);\n    }\n    for (int y = 0; y < H; y++) {\n        push_if(0, y);\n        push_if(W - 1, y);\n    }\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        int x = v % W, y = v / W;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx[d], ny = y + dy[d];\n            if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n            int nid = ny * W + nx;\n            if (!sel[nid] && !vis[nid]) {\n                vis[nid] = 1;\n                q.push(nid);\n            }\n        }\n    }\n\n    for (int i = 0; i < W * H; i++) {\n        if (!sel[i] && !vis[i]) sel[i] = 1;\n    }\n}\n\nstatic void cleanup_selection(vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int iter = 0; iter < 2; iter++) {\n        vector<char> nxt = sel;\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int id = y * W + x;\n                int cnt = 0;\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + dx[d], ny = y + dy[d];\n                    if (0 <= nx && nx < W && 0 <= ny && ny < H) {\n                        cnt += sel[ny * W + nx];\n                    }\n                }\n                if (sel[id]) {\n                    if (cnt <= 1 && cell_w[id] <= 0) nxt[id] = 0;\n                } else {\n                    if (cnt >= 3 && cell_w[id] > 0) nxt[id] = 1;\n                }\n            }\n        }\n        sel.swap(nxt);\n    }\n}\n\nstruct Component {\n    vector<int> cells;\n    int approx = 0;\n    int minx = INT_MAX, maxx = INT_MIN;\n    int miny = INT_MAX, maxy = INT_MIN;\n};\n\nstatic vector<Component> get_components(const vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    vector<char> vis(W * H, 0);\n    vector<Component> comps;\n    queue<int> q;\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int s = 0; s < W * H; s++) {\n        if (!sel[s] || vis[s]) continue;\n        vis[s] = 1;\n        q.push(s);\n\n        Component comp;\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            comp.cells.push_back(v);\n            comp.approx += cell_w[v];\n\n            int x = v % W, y = v / W;\n            comp.minx = min(comp.minx, x);\n            comp.maxx = max(comp.maxx, x);\n            comp.miny = min(comp.miny, y);\n            comp.maxy = max(comp.maxy, y);\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir];\n                int ny = y + dy[dir];\n                if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n                int nid = ny * W + nx;\n                if (sel[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        comps.push_back(move(comp));\n    }\n\n    sort(comps.begin(), comps.end(), [](const Component& a, const Component& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        return a.cells.size() > b.cells.size();\n    });\n    return comps;\n}\n\nstruct PolyInfo {\n    vector<Point> poly;\n    bool ok = false;\n};\n\nstatic PolyInfo build_polygon_from_component(\n    const vector<char>& comp_sel, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    PolyInfo res;\n    int GW = W + 1;\n    int GV = (W + 1) * (H + 1);\n    vector<int> nxt(GV, -1);\n    int edge_cnt = 0;\n\n    auto vid = [&](int x, int y) -> int {\n        return y * GW + x;\n    };\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) -> bool {\n        int a = vid(x1, y1);\n        int b = vid(x2, y2);\n        if (nxt[a] != -1) return false;\n        nxt[a] = b;\n        edge_cnt++;\n        return true;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int id = y * W + x;\n            if (!comp_sel[id]) continue;\n\n            if (y == 0 || !comp_sel[(y - 1) * W + x]) {\n                if (!add_edge(x, y, x + 1, y)) return res;\n            }\n            if (x == W - 1 || !comp_sel[y * W + (x + 1)]) {\n                if (!add_edge(x + 1, y, x + 1, y + 1)) return res;\n            }\n            if (y == H - 1 || !comp_sel[(y + 1) * W + x]) {\n                if (!add_edge(x + 1, y + 1, x, y + 1)) return res;\n            }\n            if (x == 0 || !comp_sel[y * W + (x - 1)]) {\n                if (!add_edge(x, y + 1, x, y)) return res;\n            }\n        }\n    }\n\n    if (edge_cnt == 0) return res;\n\n    int start = -1;\n    for (int i = 0; i < GV; i++) {\n        if (nxt[i] != -1) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return res;\n\n    vector<int> cyc;\n    int cur = start;\n    for (int step = 0; step <= edge_cnt + 5; step++) {\n        cyc.push_back(cur);\n        cur = nxt[cur];\n        if (cur == -1) return res;\n        if (cur == start) break;\n    }\n    if (cur != start) return res;\n    if ((int)cyc.size() != edge_cnt) return res;\n\n    auto dec = [&](int v) -> pair<int,int> {\n        return {v % GW, v / GW};\n    };\n    auto dir = [&](int a, int b) -> pair<int,int> {\n        auto [x1, y1] = dec(a);\n        auto [x2, y2] = dec(b);\n        return {(x2 > x1) - (x2 < x1), (y2 > y1) - (y2 < y1)};\n    };\n\n    vector<Point> poly;\n    int n = (int)cyc.size();\n    for (int i = 0; i < n; i++) {\n        int pv = cyc[(i - 1 + n) % n];\n        int cv = cyc[i];\n        int nv = cyc[(i + 1) % n];\n        if (dir(pv, cv) != dir(cv, nv)) {\n            auto [gx, gy] = dec(cv);\n            poly.push_back({xs[gx], ys[gy]});\n        }\n    }\n\n    if ((int)poly.size() < 4) return res;\n    res.poly = move(poly);\n    res.ok = true;\n    return res;\n}\n\nstatic Candidate max_sum_rectangle_candidate(\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    vector<int> acc(H);\n\n    for (int l = 0; l < W; l++) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int r = l; r < W; r++) {\n            for (int y = 0; y < H; y++) acc[y] += cell_w[y * W + r];\n\n            int cur = 0, st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = acc[y];\n                    st = y;\n                } else {\n                    cur += acc[y];\n                }\n                if (cur > best.approx) {\n                    int x1 = xs[l], x2 = xs[r + 1];\n                    int y1 = ys[st], y2 = ys[y + 1];\n                    if (x1 < x2 && y1 < y2) {\n                        vector<Point> poly = {\n                            {x1, y1},\n                            {x2, y1},\n                            {x2, y2},\n                            {x1, y2}\n                        };\n                        if (legal_polygon(poly)) {\n                            best.approx = cur;\n                            best.poly = move(poly);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\nstatic int nearest_cell_in_component(const Component& c, int tx, int ty, int W) {\n    int best = -1;\n    int bestd = INT_MAX;\n    for (int v : c.cells) {\n        int x = v % W;\n        int y = v / W;\n        int d = abs(x - tx) + abs(y - ty);\n        if (d < bestd) {\n            bestd = d;\n            best = v;\n        }\n    }\n    return best;\n}\n\nstatic Candidate connect_top2_components_candidate(\n    const vector<Component>& comps,\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    if ((int)comps.size() < 2) return best;\n\n    const Component& A = comps[0];\n    const Component& B = comps[1];\n\n    int txA, txB;\n    if (A.maxx < B.minx) {\n        txA = A.maxx;\n        txB = B.minx;\n    } else if (B.maxx < A.minx) {\n        txA = A.minx;\n        txB = B.maxx;\n    } else {\n        txA = txB = (max(A.minx, B.minx) + min(A.maxx, B.maxx)) / 2;\n    }\n\n    int tyA, tyB;\n    if (A.maxy < B.miny) {\n        tyA = A.maxy;\n        tyB = B.miny;\n    } else if (B.maxy < A.miny) {\n        tyA = A.miny;\n        tyB = B.maxy;\n    } else {\n        tyA = tyB = (max(A.miny, B.miny) + min(A.maxy, B.maxy)) / 2;\n    }\n\n    int va = nearest_cell_in_component(A, txA, tyA, W);\n    int vb = nearest_cell_in_component(B, txB, tyB, W);\n    if (va < 0 || vb < 0) return best;\n\n    int ax = va % W, ay = va / W;\n    int bx = vb % W, by = vb / W;\n\n    for (int mode = 0; mode < 2; mode++) {\n        vector<char> sel(W * H, 0);\n        int approx = 0;\n\n        auto add_cell = [&](int x, int y) {\n            if (x < 0 || x >= W || y < 0 || y >= H) return;\n            int id = y * W + x;\n            if (!sel[id]) {\n                sel[id] = 1;\n                approx += cell_w[id];\n            }\n        };\n\n        for (int v : A.cells) {\n            if (!sel[v]) {\n                sel[v] = 1;\n                approx += cell_w[v];\n            }\n        }\n        for (int v : B.cells) {\n            if (!sel[v]) {\n                sel[v] = 1;\n                approx += cell_w[v];\n            }\n        }\n\n        if (mode == 0) {\n            if (ax <= bx) for (int x = ax; x <= bx; x++) add_cell(x, ay);\n            else for (int x = ax; x >= bx; x--) add_cell(x, ay);\n            if (ay <= by) for (int y = ay; y <= by; y++) add_cell(bx, y);\n            else for (int y = ay; y >= by; y--) add_cell(bx, y);\n        } else {\n            if (ay <= by) for (int y = ay; y <= by; y++) add_cell(ax, y);\n            else for (int y = ay; y >= by; y--) add_cell(ax, y);\n            if (ax <= bx) for (int x = ax; x <= bx; x++) add_cell(x, by);\n            else for (int x = ax; x >= bx; x--) add_cell(x, by);\n        }\n\n        fill_holes(sel, W, H);\n        PolyInfo info = build_polygon_from_component(sel, W, H, xs, ys);\n        if (!info.ok) continue;\n        if (!legal_polygon(info.poly)) continue;\n\n        if (approx > best.approx) {\n            best.approx = approx;\n            best.poly = move(info.poly);\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TIME_LIMIT_MS = 1850.0;\n\n    int N;\n    cin >> N;\n\n    vector<WPoint> pts;\n    pts.reserve(2 * N);\n    unordered_set<uint64_t> occ;\n    occ.reserve(4 * N);\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, +1});\n        occ.insert(pack_xy(x, y));\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, -1});\n        occ.insert(pack_xy(x, y));\n    }\n\n    vector<Point> best_poly = fallback_polygon(occ);\n    int best_diff = exact_diff(best_poly, pts);\n\n    vector<Candidate> cands;\n    cands.reserve(512);\n\n    // Main cut-based search: keep it light.\n    const vector<int> cut_sizes = {1000, 750, 500};\n\n    for (int S : cut_sizes) {\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        vector<int> offsets = {0};\n        if (S / 2 > 0) offsets.push_back(S / 2);\n\n        vector<int> lambdas;\n        if (S >= 900) lambdas = {0, 1, 2, 4, 8};\n        else if (S >= 700) lambdas = {0, 1, 2, 3, 5};\n        else lambdas = {0, 1, 2, 3, 4};\n\n        for (int off : offsets) {\n            if (timer.over(TIME_LIMIT_MS)) break;\n\n            vector<int> xs = build_lines(S, off);\n            vector<int> ys = build_lines(S, off);\n            int W = (int)xs.size() - 1;\n            int H = (int)ys.size() - 1;\n\n            vector<int> cell_w(W * H, 0);\n            for (auto &p : pts) {\n                int gx = find_cell(xs, p.x);\n                int gy = find_cell(ys, p.y);\n                cell_w[gy * W + gx] += p.w;\n            }\n\n            // cheap strong candidate\n            if (!timer.over(TIME_LIMIT_MS - 250)) {\n                Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n                if (!rect.poly.empty()) cands.push_back(rect);\n            }\n\n            for (int lambda : lambdas) {\n                if (timer.over(TIME_LIMIT_MS)) break;\n\n                vector<char> sel = solve_selection_by_cut(cell_w, W, H, lambda);\n\n                bool any = false;\n                for (char c : sel) if (c) { any = true; break; }\n                if (!any) continue;\n\n                vector<char> base = sel;\n                fill_holes(base, W, H);\n\n                vector<vector<char>> variants;\n                variants.push_back(base);\n\n                if (!timer.over(TIME_LIMIT_MS - 180)) {\n                    vector<char> cleaned = base;\n                    cleanup_selection(cleaned, cell_w, W, H);\n                    fill_holes(cleaned, W, H);\n                    variants.push_back(cleaned);\n                }\n\n                for (auto &cur_sel : variants) {\n                    auto comps = get_components(cur_sel, cell_w, W, H);\n\n                    int K = min(4, (int)comps.size());\n                    for (int ci = 0; ci < K; ci++) {\n                        vector<char> comp_sel(W * H, 0);\n                        for (int v : comps[ci].cells) comp_sel[v] = 1;\n\n                        PolyInfo info = build_polygon_from_component(comp_sel, W, H, xs, ys);\n                        if (!info.ok) continue;\n                        if (!legal_polygon(info.poly)) continue;\n\n                        cands.push_back({info.poly, comps[ci].approx});\n                    }\n\n                    // Limited cheap connection candidate: only top 2 components.\n                    if (!timer.over(TIME_LIMIT_MS - 120) && (int)comps.size() >= 2) {\n                        Candidate cc = connect_top2_components_candidate(comps, cell_w, W, H, xs, ys);\n                        if (!cc.poly.empty()) cands.push_back(move(cc));\n                    }\n                }\n            }\n        }\n    }\n\n    // Rectangle-only extra search: x/y independent offsets and one finer scale.\n    if (!timer.over(TIME_LIMIT_MS - 250)) {\n        const vector<int> rect_sizes = {1000, 750, 500, 400};\n        for (int S : rect_sizes) {\n            if (timer.over(TIME_LIMIT_MS - 80)) break;\n\n            vector<int> offs = {0};\n            if (S / 2 > 0) offs.push_back(S / 2);\n\n            for (int offx : offs) {\n                for (int offy : offs) {\n                    if (timer.over(TIME_LIMIT_MS - 80)) break;\n\n                    vector<int> xs = build_lines(S, offx);\n                    vector<int> ys = build_lines(S, offy);\n                    int W = (int)xs.size() - 1;\n                    int H = (int)ys.size() - 1;\n\n                    vector<int> cell_w(W * H, 0);\n                    for (auto &p : pts) {\n                        int gx = find_cell(xs, p.x);\n                        int gy = find_cell(ys, p.y);\n                        cell_w[gy * W + gx] += p.w;\n                    }\n\n                    Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n                    if (!rect.poly.empty()) cands.push_back(move(rect));\n                }\n            }\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.poly.size() != b.poly.size()) return a.poly.size() < b.poly.size();\n        return polygon_perimeter(a.poly) < polygon_perimeter(b.poly);\n    });\n\n    auto hash_poly = [&](const vector<Point>& poly) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (auto &p : poly) {\n            h ^= uint64_t(uint32_t(p.x)) * 1000003ULL + uint32_t(p.y);\n            h *= 1099511628211ULL;\n        }\n        h ^= poly.size();\n        return h;\n    };\n\n    vector<Candidate> filtered;\n    filtered.reserve(cands.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(cands.size() * 2 + 1);\n\n    for (auto &c : cands) {\n        uint64_t h = hash_poly(c.poly);\n        if (seen.insert(h).second) filtered.push_back(move(c));\n    }\n\n    int LIMIT = min(48, (int)filtered.size());\n    for (int i = 0; i < LIMIT; i++) {\n        if (timer.over(1970.0)) break;\n        int diff = exact_diff(filtered[i].poly, pts);\n        if (diff > best_diff) {\n            best_diff = diff;\n            best_poly = filtered[i].poly;\n        }\n    }\n\n    cout << best_poly.size() << '\\n';\n    for (auto &p : best_poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing ld = long double;\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Op {\n    int p, r;\n    char d;\n    int b;\n};\n\nstruct Placed {\n    ll x = 0, y = 0, w = 0, h = 0;\n    bool used = false;\n};\n\nstruct Candidate {\n    ll estW = 0, estH = 0, est = 0;\n    bool isRow = true;\n    int anchorStrategy = 0;\n    vector<Op> ops;\n    string sig;\n\n    vector<int> rot;\n    vector<pair<int,int>> segs;\n};\n\nint N, T, sigma_;\nvector<ll> obsW, obsH;\n\nbool overlap1D(ll l1, ll r1, ll l2, ll r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nbool betterWH(ll W1, ll H1, ll W2, ll H2) {\n    if (W1 + H1 != W2 + H2) return W1 + H1 < W2 + H2;\n    if (max(W1, H1) != max(W2, H2)) return max(W1, H1) < max(W2, H2);\n    if (W1 != W2) return W1 < W2;\n    return H1 < H2;\n}\n\nbool betterCand(const Candidate& a, const Candidate& b) {\n    if (a.est != b.est) return a.est < b.est;\n    if (max(a.estW, a.estH) != max(b.estW, b.estH)) return max(a.estW, a.estH) < max(b.estW, b.estH);\n    if (a.estW != b.estW) return a.estW < b.estW;\n    if (a.estH != b.estH) return a.estH < b.estH;\n    return a.sig < b.sig;\n}\n\nvoid place_one(int p, int r, char d, int b, const vector<ll>& baseW, const vector<ll>& baseH,\n               vector<Placed>& placed, ll& W, ll& H) {\n    ll w = (r == 0 ? baseW[p] : baseH[p]);\n    ll h = (r == 0 ? baseH[p] : baseW[p]);\n\n    ll x = 0, y = 0;\n    if (d == 'U') {\n        x = (b == -1 ? 0 : placed[b].x + placed[b].w);\n        y = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(x, x + w, placed[i].x, placed[i].x + placed[i].w)) {\n                y = max(y, placed[i].y + placed[i].h);\n            }\n        }\n    } else {\n        y = (b == -1 ? 0 : placed[b].y + placed[b].h);\n        x = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(y, y + h, placed[i].y, placed[i].y + placed[i].h)) {\n                x = max(x, placed[i].x + placed[i].w);\n            }\n        }\n    }\n\n    placed[p] = {x, y, w, h, true};\n    W = max(W, x + w);\n    H = max(H, y + h);\n}\n\npair<ll,ll> simulate_ops(const vector<Op>& ops, const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<Placed> placed(N);\n    ll W = 0, H = 0;\n    for (const auto& op : ops) {\n        place_one(op.p, op.r, op.d, op.b, baseW, baseH, placed, W, H);\n    }\n    return {W, H};\n}\n\nstring ops_signature(const vector<Op>& ops) {\n    string s;\n    s.reserve(ops.size() * 5);\n    for (const auto& op : ops) {\n        s.push_back(char('0' + op.r));\n        s.push_back(op.d);\n        int x = op.b + 1;\n        s.push_back(char('A' + (x / 26)));\n        s.push_back(char('A' + (x % 26)));\n    }\n    return s;\n}\n\nvoid reevaluate(Candidate& c, const vector<ll>& evalW, const vector<ll>& evalH) {\n    auto [W, H] = simulate_ops(c.ops, evalW, evalH);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n}\n\nvector<pair<int,int>> partition_strip(const vector<ll>& primary, const vector<ll>& secondary, ll cap) {\n    vector<ll> dp(N + 1, INF64);\n    vector<int> cnt(N + 1, INT_MAX), prv(N + 1, -1);\n    dp[0] = 0;\n    cnt[0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        if (dp[i] >= INF64 / 2) continue;\n        ll sumP = 0, mxS = 0;\n        for (int j = i; j < N; j++) {\n            sumP += primary[j];\n            if (sumP > cap) break;\n            mxS = max(mxS, secondary[j]);\n\n            ll ndp = dp[i] + mxS;\n            int ncnt = cnt[i] + 1;\n            if (ndp < dp[j + 1] || (ndp == dp[j + 1] && ncnt < cnt[j + 1])) {\n                dp[j + 1] = ndp;\n                cnt[j + 1] = ncnt;\n                prv[j + 1] = i;\n            }\n        }\n    }\n\n    if (prv[N] == -1) return {};\n\n    vector<pair<int,int>> segs;\n    int cur = N;\n    while (cur > 0) {\n        int p = prv[cur];\n        segs.push_back({p, cur});\n        cur = p;\n    }\n    reverse(segs.begin(), segs.end());\n    return segs;\n}\n\nvector<ll> generate_caps(const vector<ll>& primary, const vector<ll>& secondary) {\n    ll total = 0, mx = 0;\n    ld area = 0;\n    for (int i = 0; i < N; i++) {\n        total += primary[i];\n        mx = max(mx, primary[i]);\n        area += (ld)primary[i] * (ld)secondary[i];\n    }\n\n    vector<ll> vals;\n    vals.push_back(mx);\n\n    static const ld mults1[] = {0.68L, 0.80L, 0.92L, 1.00L, 1.10L, 1.25L, 1.45L};\n    int K = min(N, 18);\n    for (int k = 1; k <= K; k++) {\n        ld base = (ld)total / (ld)k;\n        for (ld m : mults1) vals.push_back(max(mx, (ll)llround(base * m)));\n    }\n\n    ld sq = sqrt(area);\n    static const ld mults2[] = {0.55L, 0.70L, 0.85L, 1.00L, 1.20L, 1.45L, 1.80L};\n    for (ld m : mults2) vals.push_back(max(mx, (ll)llround(sq * m)));\n\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end()), vals.end());\n\n    if ((int)vals.size() > 44) {\n        vector<ll> sampled;\n        sampled.reserve(44);\n        for (int i = 0; i < 44; i++) {\n            int idx = (int)((ld)i * (ld)(vals.size() - 1) / 43.0L);\n            if (sampled.empty() || sampled.back() != vals[idx]) sampled.push_back(vals[idx]);\n        }\n        vals.swap(sampled);\n    }\n    return vals;\n}\n\nvector<vector<int>> generate_rotation_modes(const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<vector<int>> modes;\n    unordered_set<string> seen;\n\n    auto add_mode = [&](const vector<int>& rot) {\n        string s;\n        s.reserve(N);\n        for (int x : rot) s.push_back(char('0' + x));\n        if (seen.insert(s).second) modes.push_back(rot);\n    };\n\n    vector<int> all0(N, 0), all1(N, 1), minW(N), minH(N);\n    vector<ll> mxs(N);\n    for (int i = 0; i < N; i++) {\n        minW[i] = (baseW[i] <= baseH[i] ? 0 : 1);\n        minH[i] = (baseH[i] <= baseW[i] ? 0 : 1);\n        mxs[i] = max(baseW[i], baseH[i]);\n    }\n\n    add_mode(all0);\n    add_mode(all1);\n    add_mode(minW);\n    add_mode(minH);\n\n    auto sortedMx = mxs;\n    sort(sortedMx.begin(), sortedMx.end());\n    ll th1 = sortedMx[N / 2];\n    ll th2 = sortedMx[(3 * N) / 4];\n\n    vector<int> hy1(N), hy2(N), hy3(N);\n    for (int i = 0; i < N; i++) {\n        hy1[i] = (mxs[i] >= th1 ? minW[i] : minH[i]);\n        hy2[i] = (mxs[i] >= th2 ? minW[i] : minH[i]);\n        hy3[i] = (mxs[i] >= th1 ? minH[i] : minW[i]);\n    }\n    add_mode(hy1);\n    add_mode(hy2);\n    add_mode(hy3);\n\n    ll near_thr = 2LL * sigma_;\n    vector<vector<int>> bases = {minW, minH, hy1, hy2};\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int seed = 0; seed < 2; seed++) {\n            vector<int> rot = bases[bi];\n            mt19937 rng(1234567 + 1009 * bi + seed);\n            for (int i = 0; i < N; i++) {\n                if (llabs(baseW[i] - baseH[i]) <= near_thr) {\n                    if (rng() & 1) rot[i] ^= 1;\n                }\n            }\n            add_mode(rot);\n        }\n    }\n\n    return modes;\n}\n\nCandidate build_row_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& buildW, const vector<ll>& buildH) {\n    Candidate c;\n    c.isRow = true;\n    c.anchorStrategy = strategy;\n    c.rot = rot;\n    c.segs = segs;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto bottom = [&](int idx) -> ll {\n        return placed[idx].y + placed[idx].h;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'U', -1});\n            place_one(l, rot[l], 'U', -1, buildW, buildH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'L', b});\n            place_one(l, rot[l], 'L', b, buildW, buildH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'U', i - 1});\n            place_one(i, rot[i], 'U', i - 1, buildW, buildH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (bottom(i) > bottom(prevMax)) prevMax = i;\n            if (bottom(i) < bottom(prevMin)) prevMin = i;\n        }\n        if (globalMax == -1 || bottom(prevMax) > bottom(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || bottom(prevMin) < bottom(globalMin)) globalMin = prevMin;\n    }\n\n    c.ops = move(ops);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nCandidate build_col_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& buildW, const vector<ll>& buildH) {\n    Candidate c;\n    c.isRow = false;\n    c.anchorStrategy = strategy;\n    c.rot = rot;\n    c.segs = segs;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto right = [&](int idx) -> ll {\n        return placed[idx].x + placed[idx].w;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'L', -1});\n            place_one(l, rot[l], 'L', -1, buildW, buildH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'U', b});\n            place_one(l, rot[l], 'U', b, buildW, buildH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'L', i - 1});\n            place_one(i, rot[i], 'L', i - 1, buildW, buildH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (right(i) > right(prevMax)) prevMax = i;\n            if (right(i) < right(prevMin)) prevMin = i;\n        }\n        if (globalMax == -1 || right(prevMax) > right(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || right(prevMin) < right(globalMin)) globalMin = prevMin;\n    }\n\n    c.ops = move(ops);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nCandidate rebuild_candidate(bool isRow, const vector<pair<int,int>>& segs, const vector<int>& rot,\n                            int strategy, const vector<ll>& buildW, const vector<ll>& buildH,\n                            const vector<ll>& evalW, const vector<ll>& evalH) {\n    Candidate c = isRow\n        ? build_row_candidate(segs, rot, strategy, buildW, buildH)\n        : build_col_candidate(segs, rot, strategy, buildW, buildH);\n    reevaluate(c, evalW, evalH);\n    return c;\n}\n\nCandidate refine_anchor_strategy(const Candidate& base,\n                                 const vector<ll>& buildW, const vector<ll>& buildH,\n                                 const vector<ll>& evalW, const vector<ll>& evalH) {\n    Candidate best = base;\n    for (int s = 0; s < 5; s++) {\n        Candidate c = rebuild_candidate(base.isRow, base.segs, base.rot, s, buildW, buildH, evalW, evalH);\n        if (betterCand(c, best)) best = move(c);\n    }\n    return best;\n}\n\nCandidate improve_partition_structure(Candidate best,\n                                      const vector<ll>& buildW, const vector<ll>& buildH,\n                                      const vector<ll>& evalW, const vector<ll>& evalH) {\n    for (int iter = 0; iter < 3; iter++) {\n        Candidate bestLocal = best;\n\n        auto try_segs = [&](const vector<pair<int,int>>& segs2) {\n            Candidate c = rebuild_candidate(best.isRow, segs2, best.rot, best.anchorStrategy,\n                                            buildW, buildH, evalW, evalH);\n            if (betterCand(c, bestLocal)) bestLocal = move(c);\n        };\n\n        for (int s = 0; s + 1 < (int)best.segs.size(); s++) {\n            int l1 = best.segs[s].first, r1 = best.segs[s].second;\n            int l2 = best.segs[s + 1].first, r2 = best.segs[s + 1].second;\n            int len1 = r1 - l1, len2 = r2 - l2;\n\n            for (int d : {-2, -1, 1, 2}) {\n                if (d > 0) {\n                    if (len2 <= d) continue;\n                    auto segs2 = best.segs;\n                    segs2[s].second += d;\n                    segs2[s + 1].first += d;\n                    try_segs(segs2);\n                } else {\n                    int t = -d;\n                    if (len1 <= t) continue;\n                    auto segs2 = best.segs;\n                    segs2[s].second -= t;\n                    segs2[s + 1].first -= t;\n                    try_segs(segs2);\n                }\n            }\n        }\n\n        for (int s = 0; s + 1 < (int)best.segs.size(); s++) {\n            auto segs2 = best.segs;\n            segs2[s] = {segs2[s].first, segs2[s + 1].second};\n            segs2.erase(segs2.begin() + (s + 1));\n            try_segs(segs2);\n        }\n\n        for (int s = 0; s < (int)best.segs.size(); s++) {\n            int l = best.segs[s].first, r = best.segs[s].second;\n            if (r - l <= 1) continue;\n            for (int k = l + 1; k < r; k++) {\n                auto segs2 = best.segs;\n                segs2[s] = {l, k};\n                segs2.insert(segs2.begin() + s + 1, {k, r});\n                try_segs(segs2);\n            }\n        }\n\n        if (betterCand(bestLocal, best)) best = move(bestLocal);\n        else break;\n    }\n    return best;\n}\n\nCandidate improve_rotations(Candidate best, const vector<ll>& evalW, const vector<ll>& evalH) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        ll pa = evalW[a] + evalH[a];\n        ll pb = evalW[b] + evalH[b];\n        ll da = llabs(evalW[a] - evalH[a]);\n        ll db = llabs(evalW[b] - evalH[b]);\n        if (pa != pb) return pa > pb;\n        return da < db;\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (int p : order) {\n            vector<Op> ops2 = best.ops;\n            ops2[p].r ^= 1;\n            auto [W2, H2] = simulate_ops(ops2, evalW, evalH);\n            if (betterWH(W2, H2, best.estW, best.estH)) {\n                best.ops.swap(ops2);\n                best.rot[p] ^= 1;\n                best.estW = W2;\n                best.estH = H2;\n                best.est = W2 + H2;\n                best.sig = ops_signature(best.ops);\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n    return best;\n}\n\nvector<Candidate> generate_candidates_for_base(const vector<ll>& buildW, const vector<ll>& buildH,\n                                               const vector<ll>& evalW, const vector<ll>& evalH) {\n    vector<Candidate> cands;\n    unordered_set<string> usedSig;\n\n    auto add_candidate = [&](Candidate&& c) {\n        if ((int)c.ops.size() != N) return;\n        reevaluate(c, evalW, evalH);\n        if (usedSig.insert(c.sig).second) cands.push_back(move(c));\n    };\n\n    auto rotModes = generate_rotation_modes(buildW, buildH);\n\n    for (const auto& rot : rotModes) {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = (rot[i] == 0 ? buildW[i] : buildH[i]);\n            h[i] = (rot[i] == 0 ? buildH[i] : buildW[i]);\n        }\n\n        auto capsR = generate_caps(w, h);\n        for (ll cap : capsR) {\n            auto segs = partition_strip(w, h, cap);\n            if (segs.empty()) continue;\n            for (int strat = 0; strat < 5; strat++) {\n                add_candidate(build_row_candidate(segs, rot, strat, buildW, buildH));\n            }\n        }\n\n        auto capsC = generate_caps(h, w);\n        for (ll cap : capsC) {\n            auto segs = partition_strip(h, w, cap);\n            if (segs.empty()) continue;\n            for (int strat = 0; strat < 5; strat++) {\n                add_candidate(build_col_candidate(segs, rot, strat, buildW, buildH));\n            }\n        }\n    }\n\n    if (cands.empty()) {\n        vector<int> rot(N, 0);\n        vector<pair<int,int>> segs = {{0, N}};\n        add_candidate(build_row_candidate(segs, rot, 0, buildW, buildH));\n        add_candidate(build_col_candidate(segs, rot, 0, buildW, buildH));\n    }\n\n    sort(cands.begin(), cands.end(), betterCand);\n\n    int topK = min(10, (int)cands.size());\n    vector<Candidate> extra;\n    extra.reserve(topK);\n\n    for (int i = 0; i < topK; i++) {\n        Candidate c = cands[i];\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        c = improve_partition_structure(c, buildW, buildH, evalW, evalH);\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        c = improve_rotations(c, evalW, evalH);\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        if (usedSig.insert(c.sig).second) extra.push_back(move(c));\n    }\n\n    for (auto& c : extra) cands.push_back(move(c));\n    sort(cands.begin(), cands.end(), betterCand);\n    return cands;\n}\n\nvector<Candidate> generate_candidates_from_views(\n    const vector<pair<vector<ll>, vector<ll>>>& views,\n    const vector<ll>& evalW, const vector<ll>& evalH\n) {\n    vector<Candidate> all;\n    unordered_set<string> used;\n\n    for (const auto& vw : views) {\n        auto pool = generate_candidates_for_base(vw.first, vw.second, evalW, evalH);\n        for (auto& c : pool) {\n            if (used.insert(c.sig).second) all.push_back(move(c));\n        }\n    }\n\n    sort(all.begin(), all.end(), betterCand);\n    return all;\n}\n\nvoid append_unique_candidates(vector<Candidate>& candidates, vector<char>& usedFlag, vector<Candidate> add) {\n    unordered_set<string> seen;\n    seen.reserve(candidates.size() * 2 + add.size() * 2 + 1);\n    for (auto& c : candidates) seen.insert(c.sig);\n\n    for (auto& c : add) {\n        if (seen.insert(c.sig).second) {\n            candidates.push_back(move(c));\n            usedFlag.push_back(0);\n        }\n    }\n    // Do NOT sort here: usedFlag is parallel to candidates.\n    // Re-sorting without reordering usedFlag would corrupt bookkeeping.\n}\n\nvoid output_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_;\n    obsW.resize(N);\n    obsH.resize(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    int probeTurns = 0;\n    if (sigma_ >= 3000) probeTurns++;\n    if (sigma_ >= 5500) probeTurns++;\n    if (sigma_ >= 8000) probeTurns++;\n    if (sigma_ >= 9500) probeTurns++;\n    if (T >= 2 * N) probeTurns++;\n    probeTurns = min(probeTurns, max(0, T - 8));\n    probeTurns = min(probeTurns, 5);\n\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        ll ambA = max<ll>(0, 2LL * sigma_ - llabs(obsW[a] - obsH[a]));\n        ll ambB = max<ll>(0, 2LL * sigma_ - llabs(obsW[b] - obsH[b]));\n        ll sa = 2 * (obsW[a] + obsH[a]) + ambA;\n        ll sb = 2 * (obsW[b] + obsH[b]) + ambB;\n        if (sa != sb) return sa > sb;\n        return a < b;\n    });\n\n    vector<ld> sumW(N), sumH(N);\n    vector<int> cnt(N, 1);\n    for (int i = 0; i < N; i++) {\n        sumW[i] = obsW[i];\n        sumH[i] = obsH[i];\n    }\n\n    for (int t = 0; t < probeTurns; t++) {\n        int p = ord[t % N];\n        vector<Op> ops = {{p, 0, 'U', -1}};\n        output_ops(ops);\n\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n\n        sumW[p] += Wm;\n        sumH[p] += Hm;\n        cnt[p]++;\n    }\n\n    vector<ll> estW(N), estH(N);\n    for (int i = 0; i < N; i++) {\n        estW[i] = max<ll>(1, llround(sumW[i] / cnt[i]));\n        estH[i] = max<ll>(1, llround(sumH[i] / cnt[i]));\n    }\n\n    vector<pair<vector<ll>, vector<ll>>> initViews;\n    initViews.push_back({obsW, obsH});\n    bool diffRE = false;\n    for (int i = 0; i < N; i++) {\n        if (obsW[i] != estW[i] || obsH[i] != estH[i]) {\n            diffRE = true;\n            break;\n        }\n    }\n    if (diffRE) {\n        vector<ll> midW(N), midH(N);\n        for (int i = 0; i < N; i++) {\n            midW[i] = max<ll>(1, (obsW[i] + estW[i]) / 2);\n            midH[i] = max<ll>(1, (obsH[i] + estH[i]) / 2);\n        }\n        initViews.push_back({midW, midH});\n    }\n    initViews.push_back({estW, estH});\n\n    vector<Candidate> candidates = generate_candidates_from_views(initViews, estW, estH);\n    if (candidates.empty()) return 0;\n    vector<char> used(candidates.size(), 0);\n\n    auto best_by = [&](auto fn) -> int {\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = fn(candidates[i]);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    vector<int> initialPlan;\n    {\n        int x;\n        x = best_by([&](const Candidate& c) { return (ld)c.est; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return c.isRow ? (ld)c.est : 1e99L; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return (!c.isRow) ? (ld)c.est : 1e99L; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return 1.18L * (ld)c.estW + 0.82L * (ld)c.estH; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return 0.82L * (ld)c.estW + 1.18L * (ld)c.estH; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return (ld)max(c.estW, c.estH); });\n        if (x != -1) initialPlan.push_back(x);\n    }\n\n    {\n        vector<int> uniq;\n        vector<char> seen(candidates.size(), 0);\n        for (int x : initialPlan) {\n            if (x >= 0 && !seen[x]) {\n                seen[x] = 1;\n                uniq.push_back(x);\n            }\n        }\n        initialPlan.swap(uniq);\n    }\n\n    ld sumEstWQ = 0, sumEstHQ = 0;\n    ld sumMeasWQ = 0, sumMeasHQ = 0;\n    const ld prior = 1e6L;\n\n    auto pick_best_adjusted = [&]() -> int {\n        ld scaleW = (sumMeasWQ + prior) / (sumEstWQ + prior);\n        ld scaleH = (sumMeasHQ + prior) / (sumEstHQ + prior);\n\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = scaleW * (ld)candidates[i].estW + scaleH * (ld)candidates[i].estH;\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    bool regenerated = false;\n    int actualTurnsDone = 0;\n    int totalActualTurns = T - probeTurns;\n    int regenTrigger = max(3, min(6, totalActualTurns / 3));\n\n    for (int turn = probeTurns; turn < T; turn++) {\n        int localTurn = turn - probeTurns;\n        int idx = -1;\n\n        if (localTurn < (int)initialPlan.size() && !used[initialPlan[localTurn]]) {\n            idx = initialPlan[localTurn];\n        } else {\n            idx = pick_best_adjusted();\n        }\n\n        if (idx == -1) idx = 0;\n        used[idx] = 1;\n\n        output_ops(candidates[idx].ops);\n\n        ll measW, measH;\n        if (!(cin >> measW >> measH)) return 0;\n\n        sumEstWQ += (ld)candidates[idx].estW;\n        sumEstHQ += (ld)candidates[idx].estH;\n        sumMeasWQ += (ld)measW;\n        sumMeasHQ += (ld)measH;\n        actualTurnsDone++;\n\n        int turnsLeft = T - (turn + 1);\n        if (!regenerated && actualTurnsDone >= regenTrigger && turnsLeft >= 4) {\n            ld scaleW = (sumMeasWQ + prior) / (sumEstWQ + prior);\n            ld scaleH = (sumMeasHQ + prior) / (sumEstHQ + prior);\n\n            ld dev = max(fabsl(log(scaleW)), fabsl(log(scaleH)));\n            if (dev >= 0.035L) {\n                scaleW = min<ld>(1.10L, max<ld>(0.90L, scaleW));\n                scaleH = min<ld>(1.10L, max<ld>(0.90L, scaleH));\n\n                vector<ll> scaledW(N), scaledH(N), blendW(N), blendH(N);\n                for (int i = 0; i < N; i++) {\n                    scaledW[i] = max<ll>(1, llround((ld)estW[i] * scaleW));\n                    scaledH[i] = max<ll>(1, llround((ld)estH[i] * scaleH));\n                    blendW[i] = max<ll>(1, llround(((ld)estW[i] + (ld)scaledW[i]) * 0.5L));\n                    blendH[i] = max<ll>(1, llround(((ld)estH[i] + (ld)scaledH[i]) * 0.5L));\n                }\n\n                vector<pair<vector<ll>, vector<ll>>> newViews;\n                newViews.push_back({blendW, blendH});\n                newViews.push_back({scaledW, scaledH});\n\n                auto extra = generate_candidates_from_views(newViews, scaledW, scaledH);\n                append_unique_candidates(candidates, used, move(extra));\n            }\n            regenerated = true;\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> X, Y, degv;\n    vector<double> rad;\n\n    mt19937 rng{712367821};\n\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    // ---------- Build/evaluate from permutation ----------\n    long long eval_perm(const vector<int>& perm, vector<int>* out_parent = nullptr) {\n        vector<int> pos(N), depth(N, 0);\n        for (int i = 0; i < N; i++) pos[perm[i]] = i;\n\n        vector<int> parent;\n        if (out_parent) parent.assign(N, -1);\n\n        long long score = 0;\n        for (int i = 0; i < N; i++) {\n            int v = perm[i];\n            int best_d = -1;\n            int best_p = -1;\n\n            for (int u : g[v]) {\n                if (pos[u] < i) {\n                    int du = depth[u];\n                    if (du >= H) continue; // child would exceed H\n                    if (du > best_d) {\n                        best_d = du;\n                        best_p = u;\n                    } else if (du == best_d && best_p != -1) {\n                        // tie-break: prefer low beauty / high degree support\n                        if (A[u] < A[best_p] ||\n                            (A[u] == A[best_p] && degv[u] > degv[best_p])) {\n                            best_p = u;\n                        }\n                    } else if (du == best_d && best_p == -1) {\n                        best_p = u;\n                    }\n                }\n            }\n\n            if (best_p == -1) {\n                depth[v] = 0;\n                if (out_parent) parent[v] = -1;\n            } else {\n                depth[v] = best_d + 1;\n                if (out_parent) parent[v] = best_p;\n            }\n            score += 1LL * (depth[v] + 1) * A[v];\n        }\n\n        if (out_parent) *out_parent = move(parent);\n        return score;\n    }\n\n    vector<int> make_perm_by_key(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_initial_perm(int mode) {\n        vector<double> key(N, 0.0);\n\n        if (mode == 0) {\n            // low beauty first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] + 1e-6 * v;\n            }\n        } else if (mode == 1) {\n            // low beauty, high degree first\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] - 11.0 * degv[v] + 0.1 * rad[v];\n            }\n        } else if (mode == 2) {\n            // central low beauty support first\n            for (int v = 0; v < N; v++) {\n                key[v] = 8.0 * A[v] - 8.0 * degv[v] + 0.8 * rad[v];\n            }\n        } else if (mode == 3) {\n            // stronger centrality\n            for (int v = 0; v < N; v++) {\n                key[v] = 7.0 * A[v] - 10.0 * degv[v] + 1.5 * rad[v];\n            }\n        } else {\n            // randomized projection-based order\n            double theta = uniform_real_distribution<double>(0.0, 2.0 * acos(-1.0))(rng);\n            double c = cos(theta), s = sin(theta);\n            double wa = uniform_real_distribution<double>(5.0, 12.0)(rng);\n            double wd = uniform_real_distribution<double>(6.0, 14.0)(rng);\n            double wr = uniform_real_distribution<double>(0.0, 1.8)(rng);\n            double wp = uniform_real_distribution<double>(-0.7, 0.7)(rng);\n            for (int v = 0; v < N; v++) {\n                double proj = c * X[v] + s * Y[v];\n                key[v] = wa * A[v] - wd * degv[v] + wr * rad[v] + wp * proj + 1e-7 * v;\n            }\n        }\n        return make_perm_by_key(key);\n    }\n\n    // ---------- Permutation local search ----------\n    long long score_of_perm_cached(const vector<int>& perm) {\n        return eval_perm(perm, nullptr);\n    }\n\n    void random_insert_move(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        if (i < j) {\n            rotate(p.begin() + i, p.begin() + i + 1, p.begin() + j + 1);\n        } else {\n            rotate(p.begin() + j, p.begin() + i, p.begin() + i + 1);\n        }\n    }\n\n    void local_search_perm(vector<int>& perm, long long& best_score, double end_time) {\n        vector<int> cur = perm;\n        long long cur_score = best_score;\n\n        vector<int> best = perm;\n        long long best_local = best_score;\n\n        const double T0 = 1200.0;\n        const double T1 = 5.0;\n\n        while (elapsed() < end_time) {\n            double prog = min(1.0, elapsed() / end_time);\n            double temp = T0 * pow(T1 / T0, prog);\n\n            vector<int> cand = cur;\n            int type = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (type < 60) {\n                // insertion\n                int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                int v = cand[i];\n                int j;\n                if (A[v] >= 70 && i + 1 < N && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(i + 1, N - 1)(rng);\n                } else if (A[v] <= 30 && i > 0 && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(0, i - 1)(rng);\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                }\n                random_insert_move(cand, i, j);\n            } else if (type < 90) {\n                // swap\n                int i = uniform_int_distribution<int>(0, N - 2)(rng);\n                int j;\n                if (uniform_int_distribution<int>(0, 99)(rng) < 75) {\n                    j = i + 1;\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (j == i) j = (j + 1) % N;\n                }\n                swap(cand[i], cand[j]);\n            } else {\n                // small block move\n                int l = uniform_int_distribution<int>(0, N - 1)(rng);\n                int r = uniform_int_distribution<int>(0, N - 1)(rng);\n                if (l > r) swap(l, r);\n                if (r - l >= 2) {\n                    int mid = uniform_int_distribution<int>(l + 1, r)(rng);\n                    rotate(cand.begin() + l, cand.begin() + mid, cand.begin() + r + 1);\n                }\n            }\n\n            long long sc = score_of_perm_cached(cand);\n            long long diff = sc - cur_score;\n\n            bool accept = false;\n            if (diff >= 0) {\n                accept = true;\n            } else {\n                double prob = exp((double)diff / temp);\n                double rr = uniform_real_distribution<double>(0.0, 1.0)(rng);\n                if (rr < prob) accept = true;\n            }\n\n            if (accept) {\n                cur.swap(cand);\n                cur_score = sc;\n                if (sc > best_local) {\n                    best_local = sc;\n                    best = cur;\n                }\n            }\n        }\n\n        // polish by greedy adjacent swaps\n        bool improved = true;\n        while (improved && elapsed() < end_time) {\n            improved = false;\n            for (int i = 0; i + 1 < N && elapsed() < end_time; i++) {\n                swap(best[i], best[i + 1]);\n                long long sc = score_of_perm_cached(best);\n                if (sc >= best_local) {\n                    if (sc > best_local) improved = true;\n                    best_local = sc;\n                } else {\n                    swap(best[i], best[i + 1]);\n                }\n            }\n        }\n\n        perm = move(best);\n        best_score = best_local;\n    }\n\n    // ---------- Tree improvement ----------\n    struct Info {\n        vector<int> depth, tin, tout, subH;\n        vector<long long> subA;\n        long long score = 0;\n    };\n\n    Info build_info(const vector<int>& parent) {\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) {\n            if (parent[v] != -1) ch[parent[v]].push_back(v);\n        }\n\n        Info info;\n        info.depth.assign(N, 0);\n        info.tin.assign(N, 0);\n        info.tout.assign(N, 0);\n        info.subH.assign(N, 0);\n        info.subA.assign(N, 0);\n        info.score = 0;\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v) -> void {\n            info.tin[v] = timer++;\n            info.subA[v] = A[v];\n            info.subH[v] = 0;\n            info.score += 1LL * (info.depth[v] + 1) * A[v];\n            for (int c : ch[v]) {\n                info.depth[c] = info.depth[v] + 1;\n                self(self, c);\n                info.subA[v] += info.subA[c];\n                info.subH[v] = max(info.subH[v], info.subH[c] + 1);\n            }\n            info.tout[v] = timer;\n        };\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                info.depth[v] = 0;\n                dfs(dfs, v);\n            }\n        }\n        return info;\n    }\n\n    static bool is_ancestor(const Info& info, int a, int b) {\n        return info.tin[a] <= info.tin[b] && info.tout[b] <= info.tout[a];\n    }\n\n    long long improve_tree(vector<int>& parent, double end_time) {\n        long long last_score = -1;\n\n        while (elapsed() < end_time) {\n            Info info = build_info(parent);\n            last_score = info.score;\n\n            long long best_gain = 0;\n            int best_u = -1, best_v = -1;\n            int best_nd = -1;\n            long long best_sub = -1;\n\n            auto eval_move = [&](int u, int v) {\n                // move subtree rooted at v under u\n                if (parent[v] == u) return;\n                if (is_ancestor(info, v, u)) return;\n                if (info.depth[u] >= H) return;\n\n                int nd = info.depth[u] + 1;\n                if (nd <= info.depth[v]) return;\n                if (nd + info.subH[v] > H) return;\n\n                long long gain = 1LL * (nd - info.depth[v]) * info.subA[v];\n                if (gain > best_gain ||\n                    (gain == best_gain && nd > best_nd) ||\n                    (gain == best_gain && nd == best_nd && info.subA[v] > best_sub)) {\n                    best_gain = gain;\n                    best_u = u;\n                    best_v = v;\n                    best_nd = nd;\n                    best_sub = info.subA[v];\n                }\n            };\n\n            for (auto [a, b] : edges) {\n                eval_move(a, b);\n                eval_move(b, a);\n            }\n\n            if (best_gain <= 0) break;\n            parent[best_v] = best_u;\n        }\n\n        if (last_score == -1) last_score = build_info(parent).score;\n        return last_score;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            edges[i] = {u, v};\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        X.resize(N);\n        Y.resize(N);\n        for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n        st = chrono::steady_clock::now();\n\n        degv.assign(N, 0);\n        rad.assign(N, 0.0);\n        for (int v = 0; v < N; v++) {\n            degv[v] = (int)g[v].size();\n            double dx = X[v] - 500.0;\n            double dy = Y[v] - 500.0;\n            rad[v] = sqrt(dx * dx + dy * dy);\n        }\n\n        // 1) Generate multiple initial permutations\n        vector<pair<long long, vector<int>>> cand;\n        for (int mode = 0; mode <= 3; mode++) {\n            auto p = make_initial_perm(mode);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n        while ((int)cand.size() < 14 && elapsed() < 0.20) {\n            auto p = make_initial_perm(4);\n            long long sc = score_of_perm_cached(p);\n            cand.push_back({sc, move(p)});\n        }\n\n        sort(cand.begin(), cand.end(), [&](auto& a, auto& b) {\n            return a.first > b.first;\n        });\n\n        // 2) Optimize top few permutations\n        long long best_perm_score = -1;\n        vector<int> best_perm;\n        int K = min<int>(3, cand.size());\n\n        double perm_search_end = 1.45;\n        for (int i = 0; i < K && elapsed() < perm_search_end; i++) {\n            vector<int> p = cand[i].second;\n            long long sc = cand[i].first;\n\n            double remaining = perm_search_end - elapsed();\n            double slice_end = elapsed() + remaining / (K - i);\n            local_search_perm(p, sc, slice_end);\n\n            if (sc > best_perm_score) {\n                best_perm_score = sc;\n                best_perm = move(p);\n            }\n        }\n\n        if (best_perm.empty()) {\n            best_perm = cand[0].second;\n            best_perm_score = cand[0].first;\n        }\n\n        // 3) Build parent from best permutation\n        vector<int> best_parent;\n        long long base_score = eval_perm(best_perm, &best_parent);\n        long long best_score = base_score;\n\n        // 4) Final tree-based monotone improvement\n        long long improved_score = improve_tree(best_parent, TL);\n        if (improved_score > best_score) best_score = improved_score;\n\n        // Output\n        for (int v = 0; v < N; v++) {\n            if (v) cout << ' ';\n            cout << best_parent[v];\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int INF = 1e9;\nstatic constexpr int NMAX = 20;\nstatic constexpr int FMAX = 80;\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ULL;\n    XorShift(uint64_t seed = 0) {\n        x ^= seed + 0x9e3779b97f4a7c15ULL;\n        next();\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n = 0) : n(n), p(n), sz(n, 1) {\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\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\nstatic inline int popcount64(uint64_t x) {\n    return __builtin_popcountll(x);\n}\n\nstatic uint64_t zob[NMAX][NMAX][3];\nstatic bool zob_inited = false;\n\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\nstatic void init_zob() {\n    if (zob_inited) return;\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < NMAX; i++) {\n        for (int j = 0; j < NMAX; j++) {\n            for (int t = 0; t < 3; t++) {\n                seed = splitmix64(seed + 0x9e3779b97f4a7c15ULL);\n                zob[i][j][t] = seed;\n            }\n        }\n    }\n    zob_inited = true;\n}\n\nstatic uint64_t hash_board(const vector<string>& B) {\n    uint64_t h = 0;\n    for (int i = 0; i < (int)B.size(); i++) {\n        for (int j = 0; j < (int)B[i].size(); j++) {\n            int t = 0;\n            if (B[i][j] == 'x') t = 1;\n            else if (B[i][j] == 'o') t = 2;\n            h ^= zob[i][j][t];\n        }\n    }\n    return h;\n}\n\nstruct Analysis {\n    int N = 0, P = 0, F = 0;\n    vector<pair<int,int>> oni;\n    vector<int> firstRowFuku, lastRowFuku;\n    vector<int> firstColFuku, lastColFuku;\n    vector<vector<int>> reqDepth;\n    vector<vector<int>> opts;\n    vector<int> minDepth;\n    bool allSafe = true;\n    int guaranteedTail = INF;\n    int greedyTail = INF;\n};\n\nstatic int greedy_assign_upper_bound(const Analysis& A) {\n    if (A.P == 0) return 0;\n    int P = A.P, F = A.F;\n\n    vector<int> order(P);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if ((int)A.opts[a].size() != (int)A.opts[b].size())\n            return A.opts[a].size() < A.opts[b].size();\n        if (A.minDepth[a] != A.minDepth[b])\n            return A.minDepth[a] > A.minDepth[b];\n        return a < b;\n    });\n\n    vector<int> mx(F, 0);\n    for (int p : order) {\n        int bestF = -1;\n        tuple<int,int,int,int> bestKey = {INF, INF, INF, INF};\n        for (int f : A.opts[p]) {\n            int d = A.reqDepth[p][f];\n            int inc = max(0, d - mx[f]);\n            auto key = make_tuple(inc, d, mx[f], f);\n            if (key < bestKey) {\n                bestKey = key;\n                bestF = f;\n            }\n        }\n        if (bestF == -1) return INF;\n        mx[bestF] = max(mx[bestF], A.reqDepth[p][bestF]);\n    }\n\n    int cost = 0;\n    for (int f = 0; f < F; f++) cost += 2 * mx[f];\n    return cost;\n}\n\nstatic Analysis analyze_board(const vector<string>& B) {\n    int N = (int)B.size();\n    int F = 4 * N;\n\n    Analysis A;\n    A.N = N;\n    A.F = F;\n    A.firstRowFuku.assign(N, N);\n    A.lastRowFuku.assign(N, -1);\n    A.firstColFuku.assign(N, N);\n    A.lastColFuku.assign(N, -1);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (B[i][j] == 'o') {\n                A.firstRowFuku[i] = min(A.firstRowFuku[i], j);\n                A.lastRowFuku[i] = max(A.lastRowFuku[i], j);\n                A.firstColFuku[j] = min(A.firstColFuku[j], i);\n                A.lastColFuku[j] = max(A.lastColFuku[j], i);\n            } else if (B[i][j] == 'x') {\n                A.oni.push_back({i, j});\n            }\n        }\n    }\n\n    A.P = (int)A.oni.size();\n    A.reqDepth.assign(A.P, vector<int>(F, INF));\n    A.opts.assign(A.P, {});\n    A.minDepth.assign(A.P, INF);\n\n    auto idL = [&](int i) { return i; };\n    auto idR = [&](int i) { return N + i; };\n    auto idU = [&](int j) { return 2 * N + j; };\n    auto idD = [&](int j) { return 3 * N + j; };\n\n    A.allSafe = true;\n    A.guaranteedTail = 0;\n\n    for (int p = 0; p < A.P; p++) {\n        auto [i, j] = A.oni[p];\n\n        if (j < A.firstRowFuku[i]) {\n            int f = idL(i), d = j + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (j > A.lastRowFuku[i]) {\n            int f = idR(i), d = N - j;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i < A.firstColFuku[j]) {\n            int f = idU(j), d = i + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i > A.lastColFuku[j]) {\n            int f = idD(j), d = N - i;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n\n        if (A.opts[p].empty()) {\n            A.allSafe = false;\n            A.guaranteedTail = INF;\n        } else {\n            A.guaranteedTail += 2 * A.minDepth[p];\n        }\n    }\n\n    A.greedyTail = A.allSafe ? greedy_assign_upper_bound(A) : INF;\n    return A;\n}\n\nstruct MacroAction {\n    char dir;\n    int idx;\n    int k;\n    int removed;\n};\n\nstatic vector<MacroAction> generate_macro_actions(const vector<string>& B, const Analysis& A) {\n    int N = A.N;\n    vector<MacroAction> res;\n\n    for (int i = 0; i < N; i++) {\n        int limL = A.firstRowFuku[i];\n        if (limL > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limL; k++) {\n                if (B[i][k - 1] == 'x') acc++;\n                if (acc > 0) res.push_back({'L', i, k, acc});\n            }\n        }\n        int limR = (A.lastRowFuku[i] == -1 ? N : N - 1 - A.lastRowFuku[i]);\n        if (limR > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limR; k++) {\n                if (B[i][N - k] == 'x') acc++;\n                if (acc > 0) res.push_back({'R', i, k, acc});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        int limU = A.firstColFuku[j];\n        if (limU > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limU; k++) {\n                if (B[k - 1][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'U', j, k, acc});\n            }\n        }\n        int limD = (A.lastColFuku[j] == -1 ? N : N - 1 - A.lastColFuku[j]);\n        if (limD > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limD; k++) {\n                if (B[N - k][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'D', j, k, acc});\n            }\n        }\n    }\n\n    return res;\n}\n\nstatic vector<string> apply_macro(const vector<string>& B, char dir, int idx, int k) {\n    int N = (int)B.size();\n    vector<string> C = B;\n\n    if (dir == 'L') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j] = B[idx][j + k];\n        C[idx] = t;\n    } else if (dir == 'R') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j + k] = B[idx][j];\n        C[idx] = t;\n    } else if (dir == 'U') {\n        for (int i = 0; i + k < N; i++) C[i][idx] = B[i + k][idx];\n        for (int i = N - k; i < N; i++) C[i][idx] = '.';\n    } else { // D\n        for (int i = 0; i + k < N; i++) C[i + k][idx] = B[i][idx];\n        for (int i = 0; i < k; i++) C[i][idx] = '.';\n    }\n    return C;\n}\n\n// ---------- Tail solver ----------\n\nstruct Cand {\n    uint64_t mask;\n    int cost;\n    int facility;\n    int depth;\n};\n\nstatic vector<Cand> reduce_candidates(vector<Cand> v) {\n    if (v.empty()) return v;\n\n    sort(v.begin(), v.end(), [](const Cand& a, const Cand& b) {\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> dedup;\n    for (int i = 0; i < (int)v.size();) {\n        int j = i + 1;\n        Cand best = v[i];\n        while (j < (int)v.size() && v[j].mask == v[i].mask) {\n            if (v[j].cost < best.cost) best = v[j];\n            j++;\n        }\n        if (best.mask) dedup.push_back(best);\n        i = j;\n    }\n\n    sort(dedup.begin(), dedup.end(), [](const Cand& a, const Cand& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        int pa = popcount64(a.mask), pb = popcount64(b.mask);\n        if (pa != pb) return pa > pb;\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> res;\n    for (const auto& c : dedup) {\n        bool dominated = false;\n        for (const auto& d : res) {\n            if (d.cost <= c.cost && (c.mask & ~d.mask) == 0ULL) {\n                dominated = true;\n                break;\n            }\n        }\n        if (!dominated) res.push_back(c);\n    }\n    return res;\n}\n\nstruct SolveResult {\n    vector<int> depth;\n    int cost = INF;\n};\n\nstruct FacilityOption {\n    uint64_t mask;\n    int cost;\n    int depth;\n};\n\nstatic SolveResult canonicalize_and_descent(\n    int m, int F,\n    const vector<Cand>& cands,\n    const vector<int>& selectedIds\n) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> curPos(F, 0);\n    for (int id : selectedIds) {\n        int f = cands[id].facility;\n        int d = cands[id].depth;\n        for (int p = 0; p < (int)opts[f].size(); p++) {\n            if (opts[f][p].depth == d) {\n                curPos[f] = max(curPos[f], p);\n                break;\n            }\n        }\n    }\n\n    vector<int> coverCnt(m, 0);\n    auto addMask = [&](uint64_t mask, int delta) {\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverCnt[b] += delta;\n            mask &= mask - 1;\n        }\n    };\n    for (int f = 0; f < F; f++) addMask(opts[f][curPos[f]].mask, +1);\n\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int f = 0; f < F; f++) {\n            int old = curPos[f];\n            if (old == 0) continue;\n            addMask(opts[f][old].mask, -1);\n\n            int best = old;\n            for (int p = 0; p <= old; p++) {\n                uint64_t mask = opts[f][p].mask;\n                bool ok = true;\n                for (int i = 0; i < m; i++) {\n                    int c = coverCnt[i] + ((mask >> i) & 1ULL);\n                    if (c == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (ok) {\n                    best = p;\n                    break;\n                }\n            }\n\n            curPos[f] = best;\n            addMask(opts[f][curPos[f]].mask, +1);\n            if (curPos[f] != old) improved = true;\n        }\n    }\n\n    vector<int> depth(F, 0);\n    int cost = 0;\n    for (int f = 0; f < F; f++) {\n        depth[f] = opts[f][curPos[f]].depth;\n        cost += opts[f][curPos[f]].cost;\n    }\n    return {depth, cost};\n}\n\nstatic SolveResult greedy_component_heuristic(int m, int F, const vector<Cand>& cands) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> pos(F, 0);\n    uint64_t full = (m == 64 ? ~0ULL : ((1ULL << m) - 1ULL));\n    uint64_t covered = 0;\n\n    while (covered != full) {\n        int bf = -1, bp = -1, bestInc = INF, bestGain = -1, bestFinal = INF;\n        for (int f = 0; f < F; f++) {\n            for (int p = pos[f] + 1; p < (int)opts[f].size(); p++) {\n                uint64_t newbits = opts[f][p].mask & ~covered;\n                int gain = popcount64(newbits);\n                if (gain == 0) continue;\n                int inc = opts[f][p].cost - opts[f][pos[f]].cost;\n\n                if (bf == -1 ||\n                    1LL * inc * bestGain < 1LL * bestInc * gain ||\n                    (1LL * inc * bestGain == 1LL * bestInc * gain &&\n                     (gain > bestGain ||\n                      (gain == bestGain && opts[f][p].cost < bestFinal)))) {\n                    bf = f;\n                    bp = p;\n                    bestInc = inc;\n                    bestGain = gain;\n                    bestFinal = opts[f][p].cost;\n                }\n            }\n        }\n        if (bf == -1) break;\n        pos[bf] = bp;\n        covered |= opts[bf][bp].mask;\n    }\n\n    vector<int> selected;\n    for (int f = 0; f < F; f++) {\n        if (pos[f] == 0) continue;\n        int d = opts[f][pos[f]].depth;\n        for (int id = 0; id < (int)cands.size(); id++) {\n            if (cands[id].facility == f && cands[id].depth == d) {\n                selected.push_back(id);\n                break;\n            }\n        }\n    }\n    return canonicalize_and_descent(m, F, cands, selected);\n}\n\nstatic SolveResult exact_small_component(int m, int F, const vector<Cand>& cands) {\n    vector<vector<int>> coverByPoint(m);\n    for (int id = 0; id < (int)cands.size(); id++) {\n        uint64_t mask = cands[id].mask;\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverByPoint[b].push_back(id);\n            mask &= mask - 1;\n        }\n    }\n\n    for (int i = 0; i < m; i++) {\n        sort(coverByPoint[i].begin(), coverByPoint[i].end(), [&](int a, int b) {\n            int pa = popcount64(cands[a].mask), pb = popcount64(cands[b].mask);\n            if (pa != pb) return pa > pb;\n            if (cands[a].cost != cands[b].cost) return cands[a].cost < cands[b].cost;\n            return a < b;\n        });\n    }\n\n    uint32_t FULL = (m == 32 ? 0xFFFFFFFFu : ((1u << m) - 1u));\n    const uint16_t UNK = 65535;\n\n    vector<uint16_t> memo((size_t)FULL + 1, UNK);\n    vector<uint16_t> choice((size_t)FULL + 1, UNK);\n\n    function<uint16_t(uint32_t)> dfs = [&](uint32_t mask) -> uint16_t {\n        if (mask == 0) return 0;\n        uint16_t& ret = memo[mask];\n        if (ret != UNK) return ret;\n\n        int pivot = -1, bestCnt = INF;\n        uint32_t tmp = mask;\n        while (tmp) {\n            int b = __builtin_ctz(tmp);\n            int cnt = (int)coverByPoint[b].size();\n            if (cnt < bestCnt) {\n                bestCnt = cnt;\n                pivot = b;\n            }\n            tmp &= tmp - 1;\n        }\n\n        uint16_t best = UNK, bestId = UNK;\n        for (int id : coverByPoint[pivot]) {\n            uint32_t nmask = mask & ~(uint32_t)cands[id].mask;\n            uint16_t sub = dfs(nmask);\n            uint16_t val = (uint16_t)(sub + cands[id].cost);\n            if (best == UNK || val < best) {\n                best = val;\n                bestId = (uint16_t)id;\n            }\n        }\n        ret = best;\n        choice[mask] = bestId;\n        return ret;\n    };\n\n    (void)dfs(FULL);\n\n    vector<int> selected;\n    uint32_t mask = FULL;\n    while (mask) {\n        int id = choice[mask];\n        selected.push_back(id);\n        mask &= ~(uint32_t)cands[id].mask;\n    }\n    return canonicalize_and_descent(m, F, cands, selected);\n}\n\nstatic SolveResult solve_setcover_tail(const Analysis& A) {\n    SolveResult ret;\n    ret.depth.assign(A.F, 0);\n    if (!A.allSafe) return ret;\n    if (A.P == 0) {\n        ret.cost = 0;\n        return ret;\n    }\n\n    vector<Cand> gcands;\n    for (int f = 0; f < A.F; f++) {\n        vector<pair<int,int>> v;\n        for (int p = 0; p < A.P; p++) if (A.reqDepth[p][f] < INF) v.push_back({A.reqDepth[p][f], p});\n        sort(v.begin(), v.end());\n\n        uint64_t mask = 0;\n        for (int i = 0; i < (int)v.size();) {\n            int d = v[i].first;\n            while (i < (int)v.size() && v[i].first == d) {\n                mask |= (1ULL << v[i].second);\n                i++;\n            }\n            gcands.push_back({mask, 2 * d, f, d});\n        }\n    }\n\n    gcands = reduce_candidates(gcands);\n\n    DSU dsu(A.P);\n    for (const auto& c : gcands) {\n        if (popcount64(c.mask) <= 1) continue;\n        int first = __builtin_ctzll(c.mask);\n        uint64_t tmp = c.mask & (c.mask - 1);\n        while (tmp) {\n            int b = __builtin_ctzll(tmp);\n            dsu.unite(first, b);\n            tmp &= tmp - 1;\n        }\n    }\n\n    unordered_map<int, vector<int>> groups;\n    for (int p = 0; p < A.P; p++) groups[dsu.find(p)].push_back(p);\n\n    vector<int> finalDepth(A.F, 0);\n    int finalCost = 0;\n\n    for (auto& [root, pts] : groups) {\n        int m = (int)pts.size();\n        vector<int> g2l(A.P, -1);\n        for (int i = 0; i < m; i++) g2l[pts[i]] = i;\n\n        uint64_t compMask = 0;\n        for (int p : pts) compMask |= (1ULL << p);\n\n        vector<Cand> lcands;\n        for (const auto& c : gcands) {\n            if ((c.mask & compMask) == 0ULL) continue;\n            if ((c.mask & ~compMask) != 0ULL) continue;\n\n            uint64_t lmask = 0;\n            uint64_t tmp = c.mask;\n            while (tmp) {\n                int gp = __builtin_ctzll(tmp);\n                lmask |= (1ULL << g2l[gp]);\n                tmp &= tmp - 1;\n            }\n            lcands.push_back({lmask, c.cost, c.facility, c.depth});\n        }\n\n        lcands = reduce_candidates(lcands);\n\n        SolveResult comp;\n        if (m <= 22) comp = exact_small_component(m, A.F, lcands);\n        else comp = greedy_component_heuristic(m, A.F, lcands);\n\n        for (int f = 0; f < A.F; f++) finalDepth[f] = max(finalDepth[f], comp.depth[f]);\n        finalCost += comp.cost;\n    }\n\n    ret.depth = std::move(finalDepth);\n    ret.cost = finalCost;\n    return ret;\n}\n\nstatic vector<int> build_individual_fallback_depth(const Analysis& A) {\n    vector<int> depth(A.F, 0);\n    for (int p = 0; p < A.P; p++) {\n        int bestF = -1, bestD = INF;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] < bestD) {\n                bestD = A.reqDepth[p][f];\n                bestF = f;\n            }\n        }\n        if (bestF != -1) depth[bestF] = max(depth[bestF], bestD);\n    }\n    return depth;\n}\n\nstatic int depth_cost(const vector<int>& depthByFacility) {\n    int s = 0;\n    for (int d : depthByFacility) s += 2 * d;\n    return s;\n}\n\nstatic bool validate_depth_solution(const Analysis& A, const vector<int>& depthByFacility) {\n    if (!A.allSafe) return false;\n    for (int p = 0; p < A.P; p++) {\n        bool ok = false;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] <= depthByFacility[f]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nstruct MemoVal {\n    int cost = INF;\n    array<uint8_t, FMAX> depth{};\n};\n\nstatic MemoVal solve_tail_memoized(const vector<string>& board, unordered_map<uint64_t, MemoVal>& memo) {\n    uint64_t h = hash_board(board);\n    auto it = memo.find(h);\n    if (it != memo.end()) return it->second;\n\n    Analysis A = analyze_board(board);\n    MemoVal mv;\n\n    if (!A.allSafe) {\n        mv.cost = INF;\n        memo[h] = mv;\n        return mv;\n    }\n\n    SolveResult res = solve_setcover_tail(A);\n    if (!validate_depth_solution(A, res.depth)) {\n        res.depth = build_individual_fallback_depth(A);\n        res.cost = depth_cost(res.depth);\n    }\n\n    mv.cost = res.cost;\n    mv.depth.fill(0);\n    for (int f = 0; f < A.F; f++) mv.depth[f] = (uint8_t)res.depth[f];\n    memo[h] = mv;\n    return mv;\n}\n\nstatic vector<pair<char,int>> depth_to_ops(const vector<int>& depthByFacility, int N) {\n    vector<pair<char,int>> ans;\n    for (int f = 0; f < (int)depthByFacility.size(); f++) {\n        int k = depthByFacility[f];\n        if (k == 0) continue;\n        if (f < N) {\n            int i = f;\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n        } else if (f < 2 * N) {\n            int i = f - N;\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n        } else if (f < 3 * N) {\n            int j = f - 2 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n        } else {\n            int j = f - 3 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n        }\n    }\n    return ans;\n}\n\n// ---------- Search ----------\n\nstruct State {\n    vector<string> board;\n    vector<pair<char,int>> ops;\n    int g = 0;\n    int total = INF;\n    MemoVal tail;\n    uint64_t h = 0;\n};\n\nstruct ChildQuick {\n    int parent = -1;\n    MacroAction act;\n    vector<string> board;\n    int quick = INF;\n    int guaranteed = INF;\n    int g2 = INF;\n    uint64_t h = 0;\n    uint64_t key = 0;\n};\n\nstruct ChildFull {\n    vector<string> board;\n    vector<pair<char,int>> ops;\n    int g = INF;\n    int total = INF;\n    MemoVal tail;\n    uint64_t h = 0;\n    uint64_t key = 0;\n};\n\nstatic State beam_search_restart(\n    const State& init,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    XorShift& rng,\n    chrono::steady_clock::time_point deadline,\n    bool randomized,\n    int legalLimit\n) {\n    const int BEAM_WIDTH = randomized ? 4 : 6;\n    const int PER_STATE_KEEP = randomized ? 7 : 9;\n    const int GLOBAL_EXACT = randomized ? 14 : 20;\n\n    State best = init;\n    vector<State> beam = {init};\n\n    while (chrono::steady_clock::now() < deadline) {\n        vector<ChildQuick> quicks;\n        quicks.reserve(256);\n\n        for (int si = 0; si < (int)beam.size(); si++) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            const State& st = beam[si];\n            Analysis A = analyze_board(st.board);\n            if (!A.allSafe || A.P == 0) continue;\n\n            auto acts = generate_macro_actions(st.board, A);\n            if (acts.empty()) continue;\n\n            vector<ChildQuick> local;\n            local.reserve(acts.size());\n\n            for (const auto& act : acts) {\n                if (st.g + act.k > legalLimit) continue;\n\n                auto nb = apply_macro(st.board, act.dir, act.idx, act.k);\n                Analysis na = analyze_board(nb);\n                if (!na.allSafe) continue;\n                if (st.g + act.k + na.guaranteedTail > legalLimit) continue;\n\n                ChildQuick cq;\n                cq.parent = si;\n                cq.act = act;\n                cq.board = std::move(nb);\n                cq.g2 = st.g + act.k;\n                cq.quick = cq.g2 + min(na.greedyTail, na.guaranteedTail);\n                cq.guaranteed = cq.g2 + na.guaranteedTail;\n                cq.h = hash_board(cq.board);\n                cq.key = randomized ? rng.next() : 0;\n                local.push_back(std::move(cq));\n            }\n\n            sort(local.begin(), local.end(), [&](const ChildQuick& a, const ChildQuick& b) {\n                if (a.quick != b.quick) return a.quick < b.quick;\n                if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n                long long lhs = 1LL * a.act.removed * b.act.k;\n                long long rhs = 1LL * b.act.removed * a.act.k;\n                if (lhs != rhs) return lhs > rhs;\n                if (a.act.removed != b.act.removed) return a.act.removed > b.act.removed;\n                if (a.act.k != b.act.k) return a.act.k < b.act.k;\n                if (randomized && a.key != b.key) return a.key < b.key;\n                if (a.act.dir != b.act.dir) return a.act.dir < b.act.dir;\n                return a.act.idx < b.act.idx;\n            });\n\n            if ((int)local.size() > PER_STATE_KEEP) local.resize(PER_STATE_KEEP);\n            for (auto& x : local) quicks.push_back(std::move(x));\n        }\n\n        if (quicks.empty()) break;\n\n        sort(quicks.begin(), quicks.end(), [&](const ChildQuick& a, const ChildQuick& b) {\n            if (a.quick != b.quick) return a.quick < b.quick;\n            if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n            long long lhs = 1LL * a.act.removed * b.act.k;\n            long long rhs = 1LL * b.act.removed * a.act.k;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.act.removed != b.act.removed) return a.act.removed > b.act.removed;\n            if (a.act.k != b.act.k) return a.act.k < b.act.k;\n            if (randomized && a.key != b.key) return a.key < b.key;\n            if (a.act.dir != b.act.dir) return a.act.dir < b.act.dir;\n            return a.act.idx < b.act.idx;\n        });\n\n        if ((int)quicks.size() > GLOBAL_EXACT) quicks.resize(GLOBAL_EXACT);\n\n        unordered_map<uint64_t, ChildFull> uniq;\n        uniq.reserve(quicks.size() * 2 + 1);\n\n        for (auto& cq : quicks) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            MemoVal tail = solve_tail_memoized(cq.board, tailMemo);\n            if (tail.cost >= INF) continue;\n            int total = cq.g2 + tail.cost;\n            if (total > legalLimit) continue;\n\n            ChildFull cf;\n            cf.board = std::move(cq.board);\n            cf.ops = beam[cq.parent].ops;\n            for (int t = 0; t < cq.act.k; t++) cf.ops.push_back({cq.act.dir, cq.act.idx});\n            cf.g = cq.g2;\n            cf.total = total;\n            cf.tail = tail;\n            cf.h = cq.h;\n            cf.key = cq.key;\n\n            auto it = uniq.find(cf.h);\n            if (it == uniq.end() || cf.total < it->second.total || (cf.total == it->second.total && cf.g < it->second.g)) {\n                uniq[cf.h] = std::move(cf);\n            }\n        }\n\n        if (uniq.empty()) break;\n\n        vector<State> nextBeam;\n        nextBeam.reserve(uniq.size());\n        for (auto& [h, cf] : uniq) {\n            State st;\n            st.board = std::move(cf.board);\n            st.ops = std::move(cf.ops);\n            st.g = cf.g;\n            st.total = cf.total;\n            st.tail = cf.tail;\n            st.h = cf.h;\n            nextBeam.push_back(std::move(st));\n        }\n\n        sort(nextBeam.begin(), nextBeam.end(), [&](const State& a, const State& b) {\n            if (a.total != b.total) return a.total < b.total;\n            if (a.g != b.g) return a.g < b.g;\n            return a.h < b.h;\n        });\n\n        if ((int)nextBeam.size() > BEAM_WIDTH) nextBeam.resize(BEAM_WIDTH);\n\n        for (const auto& st : nextBeam) {\n            if (st.total < best.total || (st.total == best.total && st.g < best.g)) {\n                best = st;\n            }\n        }\n\n        beam = std::move(nextBeam);\n    }\n\n    return best;\n}\n\nstatic void exact_local_descent(\n    State& best,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    XorShift& rng,\n    chrono::steady_clock::time_point deadline,\n    int legalLimit\n) {\n    while (chrono::steady_clock::now() < deadline) {\n        Analysis A = analyze_board(best.board);\n        if (!A.allSafe || A.P == 0) break;\n\n        auto acts = generate_macro_actions(best.board, A);\n        if (acts.empty()) break;\n\n        struct Q {\n            MacroAction act;\n            vector<string> board;\n            int quick, guaranteed, g2;\n            uint64_t key;\n        };\n        vector<Q> qs;\n        qs.reserve(acts.size());\n\n        for (const auto& act : acts) {\n            if (best.g + act.k > legalLimit) continue;\n            auto nb = apply_macro(best.board, act.dir, act.idx, act.k);\n            Analysis na = analyze_board(nb);\n            if (!na.allSafe) continue;\n            if (best.g + act.k + na.guaranteedTail > legalLimit) continue;\n            qs.push_back({act, std::move(nb),\n                          best.g + act.k + min(na.greedyTail, na.guaranteedTail),\n                          best.g + act.k + na.guaranteedTail,\n                          best.g + act.k,\n                          rng.next()});\n        }\n\n        if (qs.empty()) break;\n\n        sort(qs.begin(), qs.end(), [&](const Q& a, const Q& b) {\n            if (a.quick != b.quick) return a.quick < b.quick;\n            if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n            long long lhs = 1LL * a.act.removed * b.act.k;\n            long long rhs = 1LL * b.act.removed * a.act.k;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.act.removed != b.act.removed) return a.act.removed > b.act.removed;\n            if (a.act.k != b.act.k) return a.act.k < b.act.k;\n            return a.key < b.key;\n        });\n\n        if ((int)qs.size() > 12) qs.resize(12);\n\n        int bestIdx = -1;\n        int bestTotal = best.total;\n        MemoVal bestTail;\n\n        for (int i = 0; i < (int)qs.size(); i++) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            MemoVal tail = solve_tail_memoized(qs[i].board, tailMemo);\n            if (tail.cost >= INF) continue;\n            int total = qs[i].g2 + tail.cost;\n            if (total < bestTotal) {\n                bestTotal = total;\n                bestIdx = i;\n                bestTail = tail;\n            }\n        }\n\n        if (bestIdx == -1) break;\n\n        for (int t = 0; t < qs[bestIdx].act.k; t++) {\n            best.ops.push_back({qs[bestIdx].act.dir, qs[bestIdx].act.idx});\n        }\n        best.board = std::move(qs[bestIdx].board);\n        best.g = qs[bestIdx].g2;\n        best.total = bestTotal;\n        best.tail = bestTail;\n        best.h = hash_board(best.board);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_zob();\n\n    int N;\n    cin >> N;\n    vector<string> originalBoard(N);\n    for (int i = 0; i < N; i++) cin >> originalBoard[i];\n\n    const int LEGAL_LIMIT = 4 * N * N; // 1600\n\n    auto start = chrono::steady_clock::now();\n    auto deadline = start + chrono::milliseconds(1850);\n\n    uint64_t seed = 0;\n    for (auto& row : originalBoard) for (char ch : row) seed = seed * 131 + ch;\n    XorShift rng(seed ^ 0x123456789abcdefULL);\n\n    unordered_map<uint64_t, MemoVal> tailMemo;\n    tailMemo.reserve(4096);\n\n    MemoVal baseTail = solve_tail_memoized(originalBoard, tailMemo);\n\n    State init;\n    init.board = originalBoard;\n    init.ops.clear();\n    init.g = 0;\n    init.total = baseTail.cost;\n    init.tail = baseTail;\n    init.h = hash_board(originalBoard);\n\n    State best = init;\n\n    int restart = 0;\n    while (chrono::steady_clock::now() < deadline - chrono::milliseconds(120)) {\n        bool randomized = (restart > 0);\n        State cand = beam_search_restart(\n            init, tailMemo, rng,\n            deadline - chrono::milliseconds(120),\n            randomized,\n            LEGAL_LIMIT\n        );\n        if (cand.total < best.total || (cand.total == best.total && cand.g < best.g)) {\n            best = std::move(cand);\n        }\n        restart++;\n        if (restart >= 6 && chrono::steady_clock::now() > deadline - chrono::milliseconds(250)) break;\n    }\n\n    exact_local_descent(best, tailMemo, rng, deadline - chrono::milliseconds(10), LEGAL_LIMIT);\n\n    vector<int> tailDepth(4 * N, 0);\n    for (int f = 0; f < 4 * N; f++) tailDepth[f] = best.tail.depth[f];\n    auto tailOps = depth_to_ops(tailDepth, N);\n\n    if ((int)best.ops.size() + (int)tailOps.size() > LEGAL_LIMIT) {\n        Analysis A = analyze_board(originalBoard);\n        vector<int> fb = build_individual_fallback_depth(A);\n        best.ops.clear();\n        tailOps = depth_to_ops(fb, N);\n    }\n\n    for (auto [c, p] : best.ops) cout << c << ' ' << p << '\\n';\n    for (auto [c, p] : tailOps) cout << c << ' ' << p << '\\n';\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\n#include <atcoder/scc>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic inline long long AbsLL(long long x) { return x >= 0 ? x : -x; }\n\nstruct State {\n    vector<int> a, b;\n    vector<int> cnt;\n    vector<int> useA, useB;\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstruct Solver {\n    int N, L;\n    vector<int> T;\n    vector<int> D; // target incoming counts: D[0]=T[0]-1, D[i]=T[i] for i>0\n    mt19937_64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver(int N_, int L_, vector<int> T_)\n        : N(N_), L(L_), T(std::move(T_)),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        st = chrono::steady_clock::now();\n        D = T;\n        D[0]--;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    State simulate(const vector<int>& a, const vector<int>& b) {\n        State res;\n        res.a = a;\n        res.b = b;\n        res.cnt.assign(N, 0);\n        res.useA.assign(N, 0);\n        res.useB.assign(N, 0);\n\n        int x = 0;\n        res.cnt[0] = 1;\n        for (int step = 1; step < L; step++) {\n            if (res.cnt[x] & 1) {\n                res.useA[x]++;\n                x = a[x];\n            } else {\n                res.useB[x]++;\n                x = b[x];\n            }\n            res.cnt[x]++;\n        }\n        res.last = x;\n\n        long long e = 0;\n        for (int i = 0; i < N; i++) e += AbsLL((long long)res.cnt[i] - T[i]);\n        res.err = e;\n        return res;\n    }\n\n    vector<vector<int>> get_sccs(const vector<int>& a, const vector<int>& b) {\n        scc_graph g(N);\n        for (int i = 0; i < N; i++) {\n            g.add_edge(i, a[i]);\n            g.add_edge(i, b[i]);\n        }\n        return g.scc();\n    }\n\n    void repair_components(vector<int>& a, vector<int>& b,\n                           const vector<int>& wA, const vector<int>& wB,\n                           vector<long long>& R) {\n        for (int iter = 0; iter < 4; iter++) {\n            auto comps = get_sccs(a, b);\n            if ((int)comps.size() <= 1) return;\n\n            int K = (int)comps.size();\n            vector<int> cid(N, -1);\n            for (int i = 0; i < K; i++) {\n                for (int v : comps[i]) cid[v] = i;\n            }\n\n            vector<int> rep(K);\n            for (int i = 0; i < K; i++) {\n                int best = comps[i][0];\n                for (int v : comps[i]) {\n                    if (T[v] < T[best]) best = v;\n                }\n                rep[i] = best;\n            }\n\n            for (int i = 0; i < K; i++) {\n                int target = rep[(i + 1) % K];\n\n                long long bestKey = (1LL << 62);\n                int bestu = -1, bestslot = -1, bestold = -1, bestw = 0;\n\n                for (int u : comps[i]) {\n                    for (int slot = 0; slot < 2; slot++) {\n                        int old = (slot == 0 ? a[u] : b[u]);\n                        int w = (slot == 0 ? wA[u] : wB[u]);\n\n                        if (old == target) {\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                            bestKey = LLONG_MIN;\n                            break;\n                        }\n\n                        long long delta =\n                            AbsLL(R[old] + w) + AbsLL(R[target] - w)\n                            - AbsLL(R[old]) - AbsLL(R[target]);\n\n                        long long key = delta * 1000000LL + w;\n                        int other = (slot == 0 ? b[u] : a[u]);\n                        if (cid[other] == i) key -= 1;\n\n                        if (key < bestKey) {\n                            bestKey = key;\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                        }\n                    }\n                    if (bestKey == LLONG_MIN) break;\n                }\n\n                if (bestu != -1 && bestold != target) {\n                    R[bestold] += bestw;\n                    R[target] -= bestw;\n                    if (bestslot == 0) a[bestu] = target;\n                    else b[bestu] = target;\n                }\n            }\n        }\n    }\n\n    pair<vector<int>, vector<int>> initial_weights_assuming_last(int last) {\n        vector<int> wA(N), wB(N);\n        for (int i = 0; i < N; i++) {\n            int departures = T[i] - (i == last ? 1 : 0);\n            if (departures < 0) departures = 0;\n            wA[i] = (departures + 1) / 2;\n            wB[i] = departures / 2;\n        }\n        return {wA, wB};\n    }\n\n    void optimize_assignment(vector<int>& dest, const vector<int>& W, vector<long long>& R) {\n        const int M = 2 * N;\n\n        for (int iter = 0; iter < 800; iter++) {\n            long long bestDelta = 0;\n            int bestType = -1; // 0: move, 1: swap\n            int bp = -1, bq = -1, bv = -1;\n\n            for (int p = 0; p < M; p++) {\n                int w = W[p];\n                if (w == 0) continue;\n                int u = dest[p];\n                for (int v = 0; v < N; v++) if (v != u) {\n                    long long delta =\n                        AbsLL(R[u] + w) + AbsLL(R[v] - w)\n                        - AbsLL(R[u]) - AbsLL(R[v]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 0;\n                        bp = p;\n                        bv = v;\n                    }\n                }\n            }\n\n            for (int p = 0; p < M; p++) {\n                int wp = W[p];\n                int u = dest[p];\n                for (int q = p + 1; q < M; q++) {\n                    int wq = W[q];\n                    int v = dest[q];\n                    if (u == v) continue;\n                    if (wp == wq) continue;\n                    long long delta =\n                        AbsLL(R[u] + wp - wq) + AbsLL(R[v] + wq - wp)\n                        - AbsLL(R[u]) - AbsLL(R[v]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            if (bestType == 0) {\n                int p = bp;\n                int w = W[p];\n                int u = dest[p];\n                int v = bv;\n                R[u] += w;\n                R[v] -= w;\n                dest[p] = v;\n            } else if (bestType == 1) {\n                int p = bp, q = bq;\n                int wp = W[p], wq = W[q];\n                int u = dest[p], v = dest[q];\n                R[u] += wp - wq;\n                R[v] += wq - wp;\n                swap(dest[p], dest[q]);\n            } else {\n                break;\n            }\n        }\n    }\n\n    State build_from_weights(const vector<int>& wA, const vector<int>& wB,\n                             const vector<int>* baseA = nullptr,\n                             const vector<int>* baseB = nullptr,\n                             int mode = 0) {\n        vector<long long> R(N);\n        for (int i = 0; i < N; i++) R[i] = D[i];\n\n        vector<int> W(2 * N), dest(2 * N, -1);\n        for (int i = 0; i < N; i++) {\n            W[2 * i] = wA[i];\n            W[2 * i + 1] = wB[i];\n        }\n\n        vector<int> ids(2 * N);\n        iota(ids.begin(), ids.end(), 0);\n        shuffle(ids.begin(), ids.end(), rng);\n        stable_sort(ids.begin(), ids.end(), [&](int p, int q) {\n            if (W[p] != W[q]) return W[p] > W[q];\n            return p < q;\n        });\n\n        long long same_pen = (mode % 4 == 0 ? 20 : mode % 4 == 1 ? 80 : mode % 4 == 2 ? 200 : 500);\n        long long self_pen = (mode % 5 == 0 ? 10 : mode % 5 == 1 ? 80 : mode % 5 == 2 ? 200 : mode % 5 == 3 ? 500 : 1200);\n        long long keep_bonus = (baseA && baseB) ? (mode % 3 == 0 ? 30 : mode % 3 == 1 ? 100 : 250) : 0;\n\n        vector<int> first_dest(N, -1);\n\n        for (int pid : ids) {\n            int owner = pid / 2;\n            int w = W[pid];\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(N);\n            for (int j = 0; j < N; j++) {\n                long long delta = AbsLL(R[j] - w) - AbsLL(R[j]);\n                long long sc = delta * 1000;\n                if (first_dest[owner] == j) sc += same_pen;\n                if (j == owner) sc += self_pen;\n                if (baseA && baseB) {\n                    int bd = (pid % 2 == 0 ? (*baseA)[owner] : (*baseB)[owner]);\n                    if (bd == j) sc -= keep_bonus;\n                }\n                sc += (long long)(rng() % 23);\n                cand.push_back({sc, j});\n            }\n\n            int pickK = min(6, N);\n            nth_element(cand.begin(), cand.begin() + (pickK - 1), cand.end());\n            sort(cand.begin(), cand.begin() + pickK);\n\n            int choose = (int)(rng() % pickK);\n            int j = cand[choose].second;\n            dest[pid] = j;\n            if (first_dest[owner] == -1) first_dest[owner] = j;\n            R[j] -= w;\n        }\n\n        optimize_assignment(dest, W, R);\n\n        vector<int> a(N), b(N);\n        for (int i = 0; i < N; i++) {\n            a[i] = dest[2 * i];\n            b[i] = dest[2 * i + 1];\n        }\n\n        repair_components(a, b, wA, wB, R);\n        return simulate(a, b);\n    }\n\n    State build_target_based(int last, const State* base, int mode) {\n        auto [wA, wB] = initial_weights_assuming_last(last);\n        if (base) return build_from_weights(wA, wB, &base->a, &base->b, mode);\n        return build_from_weights(wA, wB, nullptr, nullptr, mode);\n    }\n\n    State rebuild_from_state(const State& cur, int mode) {\n        return build_from_weights(cur.useA, cur.useB, &cur.a, &cur.b, mode);\n    }\n\n    struct MoveCand {\n        int type; // 0 redirect, 1 swap_ab, 2 swap_slots\n        long long approx;\n        int n1, s1, to;\n        int n2, s2;\n    };\n\n    State guided_local_improve(State cur, double time_limit) {\n        while (elapsed() < time_limit) {\n            vector<long long> diff(N);\n            for (int i = 0; i < N; i++) diff[i] = (long long)cur.cnt[i] - T[i];\n\n            vector<int> under, over;\n            for (int i = 0; i < N; i++) {\n                if (diff[i] < 0) under.push_back(i);\n                if (diff[i] > 0) over.push_back(i);\n            }\n            sort(under.begin(), under.end(), [&](int x, int y) { return diff[x] < diff[y]; });\n            sort(over.begin(), over.end(), [&](int x, int y) { return diff[x] > diff[y]; });\n\n            vector<int> topUnder(min<int>(12, under.size()));\n            vector<int> topOver(min<int>(12, over.size()));\n            for (int i = 0; i < (int)topUnder.size(); i++) topUnder[i] = under[i];\n            for (int i = 0; i < (int)topOver.size(); i++) topOver[i] = over[i];\n\n            vector<char> isTopUnder(N, 0), isTopOver(N, 0);\n            for (int v : topUnder) isTopUnder[v] = 1;\n            for (int v : topOver) isTopOver[v] = 1;\n\n            struct SlotInfo {\n                int node, slot, w, dest;\n            };\n            vector<SlotInfo> slots;\n            slots.reserve(2 * N);\n            for (int i = 0; i < N; i++) {\n                if (cur.useA[i] > 0) slots.push_back({i, 0, cur.useA[i], cur.a[i]});\n                if (cur.useB[i] > 0) slots.push_back({i, 1, cur.useB[i], cur.b[i]});\n            }\n\n            vector<MoveCand> cands;\n            cands.reserve(6000);\n\n            // redirect\n            for (auto &sl : slots) {\n                int w = sl.w;\n                int u = sl.dest;\n                int lim = min<int>(14, under.size());\n                for (int k = 0; k < lim; k++) {\n                    int v = under[k];\n                    if (v == u) continue;\n                    long long approx =\n                        AbsLL(diff[u] - w) + AbsLL(diff[v] + w)\n                        - AbsLL(diff[u]) - AbsLL(diff[v]);\n                    if (approx <= 0) {\n                        cands.push_back({0, approx, sl.node, sl.slot, v, -1, -1});\n                    }\n                }\n            }\n\n            // swap a_i / b_i\n            for (int i = 0; i < N; i++) {\n                if (cur.a[i] != cur.b[i]) {\n                    cands.push_back({1, 0, i, 0, 0, -1, -1});\n                }\n            }\n\n            // swap slots\n            vector<int> overSlotIds, underSlotIds;\n            for (int idx = 0; idx < (int)slots.size(); idx++) {\n                if (isTopOver[slots[idx].dest]) overSlotIds.push_back(idx);\n                if (isTopUnder[slots[idx].dest]) underSlotIds.push_back(idx);\n            }\n\n            auto cmpSlot = [&](int x, int y) {\n                if (slots[x].w != slots[y].w) return slots[x].w > slots[y].w;\n                return x < y;\n            };\n            sort(overSlotIds.begin(), overSlotIds.end(), cmpSlot);\n            sort(underSlotIds.begin(), underSlotIds.end(), cmpSlot);\n            if ((int)overSlotIds.size() > 28) overSlotIds.resize(28);\n            if ((int)underSlotIds.size() > 28) underSlotIds.resize(28);\n\n            for (int ix : overSlotIds) {\n                for (int iy : underSlotIds) {\n                    if (ix == iy) continue;\n                    const auto &p = slots[ix];\n                    const auto &q = slots[iy];\n                    if (p.dest == q.dest) continue;\n                    if (p.w == q.w) continue;\n\n                    int u = p.dest, v = q.dest;\n                    long long approx =\n                        AbsLL(diff[u] - p.w + q.w) + AbsLL(diff[v] - q.w + p.w)\n                        - AbsLL(diff[u]) - AbsLL(diff[v]);\n\n                    if (approx <= 0) {\n                        cands.push_back({2, approx, p.node, p.slot, 0, q.node, q.slot});\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            shuffle(cands.begin(), cands.end(), rng);\n            stable_sort(cands.begin(), cands.end(), [&](const MoveCand& x, const MoveCand& y) {\n                return x.approx < y.approx;\n            });\n\n            int evals = min<int>(18, cands.size());\n            State bestNext = cur;\n            bool improved = false;\n\n            for (int idx = 0; idx < evals && elapsed() < time_limit; idx++) {\n                const auto& cd = cands[idx];\n                vector<int> na = cur.a, nb = cur.b;\n\n                if (cd.type == 0) {\n                    if (cd.s1 == 0) {\n                        if (na[cd.n1] == cd.to) continue;\n                        na[cd.n1] = cd.to;\n                    } else {\n                        if (nb[cd.n1] == cd.to) continue;\n                        nb[cd.n1] = cd.to;\n                    }\n                } else if (cd.type == 1) {\n                    swap(na[cd.n1], nb[cd.n1]);\n                } else {\n                    int d1 = (cd.s1 == 0 ? na[cd.n1] : nb[cd.n1]);\n                    int d2 = (cd.s2 == 0 ? na[cd.n2] : nb[cd.n2]);\n                    if (d1 == d2) continue;\n                    if (cd.s1 == 0) na[cd.n1] = d2;\n                    else nb[cd.n1] = d2;\n                    if (cd.s2 == 0) na[cd.n2] = d1;\n                    else nb[cd.n2] = d1;\n                }\n\n                State nxt = simulate(na, nb);\n                if (nxt.err < bestNext.err) {\n                    bestNext = std::move(nxt);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            cur = std::move(bestNext);\n        }\n        return cur;\n    }\n\n    State solve() {\n        State best;\n        best.err = (1LL << 60);\n\n        vector<int> pos;\n        for (int i = 0; i < N; i++) if (T[i] > 0) pos.push_back(i);\n        sort(pos.begin(), pos.end(), [&](int x, int y) {\n            if (T[x] != T[y]) return T[x] > T[y];\n            return x < y;\n        });\n        if (pos.empty()) pos.push_back(0);\n\n        int mode = 0;\n        int ptr = 0;\n\n        // Initial exploration\n        while (elapsed() < 0.36) {\n            int last;\n            if (ptr < min<int>(14, pos.size())) last = pos[ptr];\n            else last = pos[(int)(rng() % pos.size())];\n            State cand = build_target_based(last, nullptr, mode++);\n            if (cand.err < best.err) best = std::move(cand);\n            ptr++;\n        }\n\n        // Main search\n        int stagnation = 0;\n        while (elapsed() < 1.78) {\n            State cand;\n            int typ = mode % 5;\n\n            if (typ == 0) {\n                cand = rebuild_from_state(best, mode++);\n            } else if (typ == 1) {\n                cand = build_target_based(best.last, &best, mode++);\n            } else if (typ == 2) {\n                int last = pos[(int)(rng() % min<int>(14, pos.size()))];\n                cand = build_target_based(last, &best, mode++);\n            } else if (typ == 3) {\n                int last = pos[(int)(rng() % pos.size())];\n                cand = build_target_based(last, &best, mode++);\n            } else {\n                int last = pos[(int)(rng() % pos.size())];\n                cand = build_target_based(last, nullptr, mode++);\n            }\n\n            if (cand.err <= best.err + 1200 && elapsed() < 1.90) {\n                double lim = min(1.91, elapsed() + 0.030);\n                cand = guided_local_improve(std::move(cand), lim);\n            }\n\n            if (cand.err < best.err) {\n                best = std::move(cand);\n                stagnation = 0;\n            } else {\n                stagnation++;\n            }\n\n            if (stagnation >= 4 && elapsed() < 1.90) {\n                State alt = guided_local_improve(best, min(1.92, elapsed() + 0.020));\n                if (alt.err < best.err) {\n                    best = std::move(alt);\n                    stagnation = 0;\n                } else {\n                    stagnation = 0;\n                }\n            }\n        }\n\n        // Final intensification: repeatedly rebuild from the current best and polish.\n        while (elapsed() < 1.95) {\n            State cand = rebuild_from_state(best, mode++);\n            cand = guided_local_improve(std::move(cand), min(1.965, elapsed() + 0.020));\n            if (cand.err < best.err) best = std::move(cand);\n            else break;\n        }\n\n        best = guided_local_improve(std::move(best), 1.985);\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    vector<int> T(N);\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    Solver solver(N, L, T);\n    State ans = solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << ans.a[i] << ' ' << ans.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a);\n        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\nstruct Solver {\n    static constexpr double INF = 1e100;\n    static constexpr double PI = 3.1415926535897932384626433832795;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<double> cx, cy;\n    vector<vector<double>> distm;\n    vector<uint32_t> morton_code, hilbert_code;\n    int used_queries = 0;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffff;\n        x = (x ^ (x << 8)) & 0x00FF00FF;\n        x = (x ^ (x << 4)) & 0x0F0F0F0F;\n        x = (x ^ (x << 2)) & 0x33333333;\n        x = (x ^ (x << 1)) & 0x55555555;\n        return x;\n    }\n\n    static void rot_hilbert(int n, int &x, int &y, int rx, int ry) {\n        if (ry == 0) {\n            if (rx == 1) {\n                x = n - 1 - x;\n                y = n - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    static uint32_t hilbert_xy2d(int bits, int x, int y) {\n        int n = 1 << bits;\n        uint32_t d = 0;\n        for (int s = n >> 1; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (uint32_t)(s * s) * (uint32_t)((3 * rx) ^ ry);\n            rot_hilbert(s, x, y, rx, ry);\n        }\n        return d;\n    }\n\n    static pair<int,int> norm_edge(int a, int b) {\n        if (a > b) swap(a, b);\n        return {a, b};\n    }\n\n    static uint64_t edge_key(int a, int b) {\n        if (a > b) swap(a, b);\n        return (uint64_t(uint32_t(a)) << 32) | uint32_t(b);\n    }\n\n    static uint64_t hash_vec_ordered(const vector<int>& v) {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : v) {\n            h ^= uint64_t(x + 1);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    vector<int> reversed_copy(const vector<int>& v) {\n        vector<int> r = v;\n        reverse(r.begin(), r.end());\n        return r;\n    }\n\n    void input() {\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        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx.resize(N); cy.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n        }\n\n        distm.assign(N, vector<double>(N, 0.0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                double dx = cx[i] - cx[j];\n                double dy = cy[i] - cy[j];\n                double d = sqrt(dx * dx + dy * dy);\n                distm[i][j] = distm[j][i] = d;\n            }\n        }\n\n        morton_code.resize(N);\n        hilbert_code.resize(N);\n        for (int i = 0; i < N; i++) {\n            int xi = int(round(cx[i]));\n            int yi = int(round(cy[i]));\n            xi = max(0, min(16383, xi));\n            yi = max(0, min(16383, yi));\n            morton_code[i] = part1by1((uint32_t)xi) | (part1by1((uint32_t)yi) << 1);\n            hilbert_code[i] = hilbert_xy2d(14, xi, yi);\n        }\n    }\n\n    vector<int> make_morton_order() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_hilbert_order() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (hilbert_code[a] != hilbert_code[b]) return hilbert_code[a] < hilbert_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_projection_order(double theta) {\n        double ct = cos(theta), st = sin(theta);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double ka = cx[a] * ct + cy[a] * st;\n            double kb = cx[b] * ct + cy[b] * st;\n            if (fabs(ka - kb) > 1e-9) return ka < kb;\n            double ta = -cx[a] * st + cy[a] * ct;\n            double tb = -cx[b] * st + cy[b] * ct;\n            if (fabs(ta - tb) > 1e-9) return ta < tb;\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_group_by_key(const vector<int>& group, int mode) {\n        vector<int> ord = group;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto key = [&](int v) -> pair<double,double> {\n                if (mode == 0) return {cx[v], cy[v]};\n                if (mode == 1) return {cy[v], cx[v]};\n                if (mode == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n                if (mode == 3) return {cx[v] - cy[v], cx[v] + cy[v]};\n                if (mode == 4) return {double(morton_code[v]), double(v)};\n                return {double(hilbert_code[v]), double(v)};\n            };\n            auto ka = key(a), kb = key(b);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n        return ord;\n    }\n\n    double mst_cost_of_list(const vector<int>& cities) {\n        int n = (int)cities.size();\n        if (n <= 1) return 0.0;\n        vector<double> md(n, INF);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n        double ret = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            ret += md[v];\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) md[i] = d;\n            }\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_small(const vector<int>& cities) {\n        int n = (int)cities.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<double> md(n, INF);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back(norm_edge(cities[v], cities[par[v]]));\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) {\n                    md[i] = d;\n                    par[i] = v;\n                }\n            }\n        }\n        return edges;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_full(const vector<int>& cities) {\n        return approx_mst_edges_small(cities);\n    }\n\n    vector<int> mst_preorder_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        auto edges = approx_mst_edges_full(group);\n        unordered_map<int, vector<int>> adj;\n        adj.reserve(n * 2);\n        for (auto [a, b] : edges) {\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        }\n\n        int root = group[0];\n        for (int v : group) {\n            if (cx[v] + cy[v] < cx[root] + cy[root]) root = v;\n        }\n\n        vector<int> ord;\n        ord.reserve(n);\n        unordered_set<int> vis;\n        vis.reserve(n * 2);\n\n        vector<pair<int,int>> st;\n        st.push_back({root, -1});\n        while (!st.empty()) {\n            auto [v, p] = st.back();\n            st.pop_back();\n            if (vis.count(v)) continue;\n            vis.insert(v);\n            ord.push_back(v);\n\n            auto neis = adj[v];\n            sort(neis.begin(), neis.end(), [&](int a, int b) {\n                double da = distm[v][a], db = distm[v][b];\n                if (fabs(da - db) > 1e-9) return da > db;\n                return a > b;\n            });\n            for (int to : neis) if (to != p && !vis.count(to)) {\n                st.push_back({to, v});\n            }\n        }\n        if ((int)ord.size() != n) return group;\n        return ord;\n    }\n\n    vector<int> nearest_neighbor_order(const vector<int>& group, int start_mode) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        int start = group[0];\n        if (start_mode == 0) {\n            for (int v : group) if (cx[v] + cy[v] < cx[start] + cy[start]) start = v;\n        } else {\n            double gx = 0.0, gy = 0.0;\n            for (int v : group) gx += cx[v], gy += cy[v];\n            gx /= n; gy /= n;\n            double bestd = -1.0;\n            for (int v : group) {\n                double dx = cx[v] - gx, dy = cy[v] - gy;\n                double d = dx * dx + dy * dy;\n                if (d > bestd) bestd = d, start = v;\n            }\n        }\n\n        unordered_set<int> rem(group.begin(), group.end());\n        rem.reserve(n * 2);\n        vector<int> ord;\n        ord.reserve(n);\n        int cur = start;\n        ord.push_back(cur);\n        rem.erase(cur);\n\n        while (!rem.empty()) {\n            int best = -1;\n            double bd = INF;\n            for (int v : rem) {\n                double d = distm[cur][v];\n                if (d < bd - 1e-9 || (fabs(d - bd) <= 1e-9 && (best == -1 || v < best))) {\n                    bd = d;\n                    best = v;\n                }\n            }\n            cur = best;\n            ord.push_back(cur);\n            rem.erase(cur);\n        }\n        return ord;\n    }\n\n    struct OrderEvaluator {\n        const vector<int>& ord;\n        const vector<vector<double>>& distm;\n        int N;\n        vector<vector<double>> cache;\n\n        OrderEvaluator(const vector<int>& ord_, const vector<vector<double>>& distm_)\n            : ord(ord_), distm(distm_), N((int)ord_.size()),\n              cache(N + 1, vector<double>(N + 1, -1.0)) {}\n\n        double seg_cost(int l, int len) {\n            if (len <= 1) return 0.0;\n            double &res = cache[l][len];\n            if (res >= -0.5) return res;\n\n            vector<double> md(len, 1e100);\n            vector<char> used(len, 0);\n            md[0] = 0.0;\n            double ret = 0.0;\n\n            for (int it = 0; it < len; it++) {\n                int v = -1;\n                for (int i = 0; i < len; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                ret += md[v];\n                int cv = ord[l + v];\n                for (int i = 0; i < len; i++) if (!used[i]) {\n                    double d = distm[cv][ord[l + i]];\n                    if (d < md[i]) md[i] = d;\n                }\n            }\n            res = ret;\n            return res;\n        }\n\n        double total_cost(const vector<int>& sizes) {\n            int pos = 0;\n            double ret = 0.0;\n            for (int s : sizes) {\n                ret += seg_cost(pos, s);\n                pos += s;\n            }\n            return ret;\n        }\n\n        vector<int> improve(vector<int> sizes, int passes = 4) {\n            int m = (int)sizes.size();\n            for (int pass = 0; pass < passes; pass++) {\n                bool any = false;\n                int pos = 0;\n                for (int i = 0; i + 1 < m; i++) {\n                    int a = sizes[i], b = sizes[i + 1];\n                    double oldc = seg_cost(pos, a) + seg_cost(pos + a, b);\n                    double newc = seg_cost(pos, b) + seg_cost(pos + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[i], sizes[i + 1]);\n                        any = true;\n                    }\n                    pos += sizes[i];\n                }\n                if (!any) break;\n            }\n            return sizes;\n        }\n    };\n\n    struct Candidate {\n        vector<vector<int>> groups_seq;\n        double score = INF;\n    };\n\n    Candidate candidate_from_order(const vector<int>& ord, const vector<int>& size_seq) {\n        OrderEvaluator eval(ord, distm);\n        auto sizes = eval.improve(size_seq, 5);\n        double sc = eval.total_cost(sizes);\n\n        vector<vector<int>> groups;\n        int pos = 0;\n        for (int s : sizes) {\n            vector<int> grp;\n            grp.reserve(s);\n            for (int i = 0; i < s; i++) grp.push_back(ord[pos + i]);\n            pos += s;\n            groups.push_back(move(grp));\n        }\n        return {groups, sc};\n    }\n\n    vector<vector<int>> kd_partition_rec(vector<int> cities, vector<int> sizes, int mode, int depth) {\n        if ((int)sizes.size() == 1) return {cities};\n\n        int total = 0;\n        for (int x : sizes) total += x;\n\n        int pref = 0;\n        int split_k = 1;\n        int best_diff = total;\n        for (int k = 1; k < (int)sizes.size(); k++) {\n            pref += sizes[k - 1];\n            int diff = abs(total - 2 * pref);\n            if (diff < best_diff) {\n                best_diff = diff;\n                split_k = k;\n            }\n        }\n\n        int left_need = 0;\n        for (int i = 0; i < split_k; i++) left_need += sizes[i];\n\n        auto choose_mode_key = [&](int v, int chosen) -> pair<double,double> {\n            if (chosen == 0) return {cx[v], cy[v]};\n            if (chosen == 1) return {cy[v], cx[v]};\n            if (chosen == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n            return {cx[v] - cy[v], cx[v] + cy[v]};\n        };\n\n        int chosen = 0;\n        if (mode == 0) {\n            double minx = 1e18, maxx = -1e18, miny = 1e18, maxy = -1e18;\n            for (int v : cities) {\n                minx = min(minx, cx[v]);\n                maxx = max(maxx, cx[v]);\n                miny = min(miny, cy[v]);\n                maxy = max(maxy, cy[v]);\n            }\n            chosen = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        } else if (mode == 1) {\n            chosen = depth % 2;\n        } else {\n            double mina = 1e18, maxa = -1e18, minb = 1e18, maxb = -1e18;\n            for (int v : cities) {\n                double a = cx[v] + cy[v];\n                double b = cx[v] - cy[v];\n                mina = min(mina, a); maxa = max(maxa, a);\n                minb = min(minb, b); maxb = max(maxb, b);\n            }\n            chosen = ((maxa - mina) >= (maxb - minb)) ? 2 : 3;\n        }\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            auto ka = choose_mode_key(a, chosen);\n            auto kb = choose_mode_key(b, chosen);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n\n        vector<int> left_cities(cities.begin(), cities.begin() + left_need);\n        vector<int> right_cities(cities.begin() + left_need, cities.end());\n        vector<int> left_sizes(sizes.begin(), sizes.begin() + split_k);\n        vector<int> right_sizes(sizes.begin() + split_k, sizes.end());\n\n        auto gl = kd_partition_rec(left_cities, left_sizes, mode, depth + 1);\n        auto gr = kd_partition_rec(right_cities, right_sizes, mode, depth + 1);\n        gl.insert(gl.end(), gr.begin(), gr.end());\n        return gl;\n    }\n\n    Candidate candidate_from_kd(const vector<int>& size_seq, int mode) {\n        vector<int> cities(N);\n        iota(cities.begin(), cities.end(), 0);\n        auto groups = kd_partition_rec(cities, size_seq, mode, 0);\n        double sc = 0.0;\n        for (auto &g : groups) sc += mst_cost_of_list(g);\n        return {groups, sc};\n    }\n\n    vector<vector<int>> assign_to_original_indices(const vector<vector<int>>& groups_seq) {\n        unordered_map<int, vector<int>> mp;\n        mp.reserve(M * 2);\n        for (int i = 0; i < M; i++) mp[G[i]].push_back(i);\n        for (auto &kv : mp) reverse(kv.second.begin(), kv.second.end());\n\n        vector<vector<int>> ret(M);\n        for (auto &grp : groups_seq) {\n            int s = (int)grp.size();\n            int idx = mp[s].back();\n            mp[s].pop_back();\n            ret[idx] = grp;\n        }\n        return ret;\n    }\n\n    double sqdist_city_to_point(int v, double x, double y) {\n        double dx = cx[v] - x;\n        double dy = cy[v] - y;\n        return dx * dx + dy * dy;\n    }\n\n    void recompute_group_info(const vector<vector<int>>& groups, int gid,\n                              vector<double>& gcx, vector<double>& gcy, vector<double>& gcost) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[gid]) {\n            sx += cx[v];\n            sy += cy[v];\n        }\n        gcx[gid] = sx / groups[gid].size();\n        gcy[gid] = sy / groups[gid].size();\n        gcost[gid] = mst_cost_of_list(groups[gid]);\n    }\n\n    void local_swap_optimize(vector<vector<int>>& groups) {\n        vector<double> gcx(M), gcy(M), gcost(M);\n        for (int i = 0; i < M; i++) recompute_group_info(groups, i, gcx, gcy, gcost);\n\n        const int PASSES = 2;\n        const int K_NEI = 5;\n        const int K_CAND = 4;\n\n        for (int pass = 0; pass < PASSES; pass++) {\n            bool any = false;\n\n            vector<vector<int>> neigh(M);\n            for (int i = 0; i < M; i++) {\n                vector<pair<double,int>> ds;\n                ds.reserve(M - 1);\n                for (int j = 0; j < M; j++) if (i != j) {\n                    double dx = gcx[i] - gcx[j];\n                    double dy = gcy[i] - gcy[j];\n                    ds.push_back({dx * dx + dy * dy, j});\n                }\n                int k = min(K_NEI, (int)ds.size());\n                if (k == 0) continue;\n                if (k < (int)ds.size()) nth_element(ds.begin(), ds.begin() + k, ds.end());\n                sort(ds.begin(), ds.begin() + k);\n                for (int t = 0; t < k; t++) neigh[i].push_back(ds[t].second);\n            }\n\n            set<pair<int,int>> pairs;\n            for (int i = 0; i < M; i++) {\n                for (int j : neigh[i]) {\n                    if (i < j) pairs.insert({i, j});\n                    else pairs.insert({j, i});\n                }\n            }\n\n            for (auto [a, b] : pairs) {\n                auto pick_candidates = [&](int from, int to) {\n                    vector<pair<double,int>> cand;\n                    cand.reserve(groups[from].size());\n                    for (int idx = 0; idx < (int)groups[from].size(); idx++) {\n                        int v = groups[from][idx];\n                        double score = sqdist_city_to_point(v, gcx[to], gcy[to])\n                                     - sqdist_city_to_point(v, gcx[from], gcy[from]);\n                        cand.push_back({score, idx});\n                    }\n                    int k = min(K_CAND, (int)cand.size());\n                    if (k == 0) return vector<int>{};\n                    if (k < (int)cand.size()) nth_element(cand.begin(), cand.begin() + k, cand.end());\n                    sort(cand.begin(), cand.begin() + k);\n                    vector<int> ret;\n                    for (int i = 0; i < k; i++) ret.push_back(cand[i].second);\n                    return ret;\n                };\n\n                auto ca = pick_candidates(a, b);\n                auto cb = pick_candidates(b, a);\n\n                double old_cost = gcost[a] + gcost[b];\n                double best_new = old_cost;\n                int besta = -1, bestb = -1;\n\n                for (int ia : ca) {\n                    for (int ib : cb) {\n                        vector<int> ga = groups[a];\n                        vector<int> gb = groups[b];\n                        swap(ga[ia], gb[ib]);\n                        double nc = mst_cost_of_list(ga) + mst_cost_of_list(gb);\n                        if (nc + 1e-9 < best_new) {\n                            best_new = nc;\n                            besta = ia;\n                            bestb = ib;\n                        }\n                    }\n                }\n\n                if (besta != -1) {\n                    swap(groups[a][besta], groups[b][bestb]);\n                    recompute_group_info(groups, a, gcx, gcy, gcost);\n                    recompute_group_info(groups, b, gcx, gcy, gcost);\n                    any = true;\n                }\n            }\n\n            if (!any) break;\n        }\n    }\n\n    vector<vector<int>> build_groups() {\n        vector<Candidate> cands;\n\n        vector<int> ascG = G;\n        sort(ascG.begin(), ascG.end());\n        vector<int> descG = G;\n        sort(descG.rbegin(), descG.rend());\n        vector<vector<int>> size_seqs = {G, ascG, descG};\n\n        vector<vector<int>> orders_raw;\n        orders_raw.push_back(make_morton_order());\n        orders_raw.push_back(make_hilbert_order());\n        orders_raw.push_back(make_projection_order(0.0));\n        orders_raw.push_back(make_projection_order(PI / 2.0));\n        orders_raw.push_back(make_projection_order(PI / 4.0));\n        orders_raw.push_back(make_projection_order(-PI / 4.0));\n        orders_raw.push_back(make_projection_order(PI / 8.0));\n        orders_raw.push_back(make_projection_order(3.0 * PI / 8.0));\n\n        vector<vector<int>> orders;\n        unordered_set<uint64_t> seen;\n        for (auto &ord : orders_raw) {\n            uint64_t h1 = hash_vec_ordered(ord);\n            if (!seen.count(h1)) {\n                seen.insert(h1);\n                orders.push_back(ord);\n            }\n            auto rev = reversed_copy(ord);\n            uint64_t h2 = hash_vec_ordered(rev);\n            if (!seen.count(h2)) {\n                seen.insert(h2);\n                orders.push_back(move(rev));\n            }\n        }\n\n        for (auto &ord : orders) {\n            for (auto &sz : size_seqs) cands.push_back(candidate_from_order(ord, sz));\n        }\n\n        for (auto &sz : size_seqs) {\n            for (int mode = 0; mode < 3; mode++) {\n                cands.push_back(candidate_from_kd(sz, mode));\n            }\n        }\n\n        Candidate best;\n        best.score = INF;\n        for (auto &c : cands) {\n            if (c.score < best.score) best = c;\n        }\n\n        auto groups = assign_to_original_indices(best.groups_seq);\n        local_swap_optimize(groups);\n        return groups;\n    }\n\n    vector<pair<int,int>> make_primary_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n < 2) return res;\n        int s = 0;\n        while (true) {\n            int len = min(L, n - s);\n            if (len < 2) break;\n            res.push_back({s, len});\n            if (s + len >= n) break;\n            s = s + len - 1;\n        }\n        return res;\n    }\n\n    vector<pair<int,int>> make_extra_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n <= L) return res;\n\n        auto primary = make_primary_windows_indices(n);\n        set<int> used_starts;\n        for (auto [s, len] : primary) used_starts.insert(s);\n\n        int max_start = n - L;\n        int shift = max(1, (L - 1) / 2);\n\n        for (int i = 0; i + 1 < (int)primary.size(); i++) {\n            int s1 = primary[i].first;\n            int s2 = primary[i + 1].first;\n            int cand = min(max_start, s1 + shift);\n            if (cand > s1 && cand < s2 && !used_starts.count(cand)) {\n                used_starts.insert(cand);\n                res.push_back({cand, L});\n            }\n            int cand2 = max(0, min(max_start, s2 - shift));\n            if (cand2 > s1 && cand2 < s2 && !used_starts.count(cand2)) {\n                used_starts.insert(cand2);\n                res.push_back({cand2, L});\n            }\n        }\n        return res;\n    }\n\n    // candidate edge set \u304b\u3089\u3001\u307e\u305a\u305d\u306e\u8fba\u3060\u3051\u3067 forest \u3092\u4f5c\u308a\u3001\n    // \u9023\u7d50\u6210\u5206\u9593\u3092\u6700\u77ed\u63a8\u5b9a\u8fba\u3067\u88dc\u5b8c\u3057\u3066\u5168\u4f53\u30b3\u30b9\u30c8\u3092\u898b\u7a4d\u3082\u308b\u3002\n    double completed_tree_cost_from_keys(const vector<int>& group,\n                                         const unordered_set<uint64_t>& eset) {\n        int n = (int)group.size();\n        if (n <= 1) return 0.0;\n\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        double cost = 0.0;\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) cost += e.first;\n        }\n\n        unordered_map<int, int> comp_id;\n        comp_id.reserve(n * 2);\n        int cc = 0;\n        for (int v : group) {\n            int r = dsu.find(v);\n            if (!comp_id.count(r)) comp_id[r] = cc++;\n        }\n        if (cc <= 1) return cost;\n\n        vector<vector<double>> best(cc, vector<double>(cc, INF));\n        for (int i = 0; i < n; i++) {\n            int u = group[i];\n            int cu = comp_id[dsu.find(u)];\n            for (int j = i + 1; j < n; j++) {\n                int v = group[j];\n                int cv = comp_id[dsu.find(v)];\n                if (cu == cv) continue;\n                double d = distm[u][v];\n                if (d < best[cu][cv]) {\n                    best[cu][cv] = best[cv][cu] = d;\n                }\n            }\n        }\n\n        vector<double> md(cc, INF);\n        vector<char> used(cc, 0);\n        md[0] = 0.0;\n        for (int it = 0; it < cc; it++) {\n            int v = -1;\n            for (int i = 0; i < cc; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            cost += md[v];\n            for (int to = 0; to < cc; to++) if (!used[to] && best[v][to] < md[to]) {\n                md[to] = best[v][to];\n            }\n        }\n        return cost;\n    }\n\n    double approx_union_tree_cost_for_order(const vector<int>& ord) {\n        int n = (int)ord.size();\n        if (n <= 1) return 0.0;\n        if (n <= L) return mst_cost_of_list(ord);\n\n        auto primary = make_primary_windows_indices(n);\n        unordered_set<uint64_t> eset;\n        eset.reserve(n * 8);\n\n        for (auto [s, len] : primary) {\n            vector<int> w(ord.begin() + s, ord.begin() + s + len);\n            auto e = approx_mst_edges_small(w);\n            for (auto [a, b] : e) eset.insert(edge_key(a, b));\n        }\n        return completed_tree_cost_from_keys(ord, eset);\n    }\n\n    vector<int> choose_best_local_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        vector<vector<int>> raw;\n        raw.push_back(group);\n        raw.push_back(order_group_by_key(group, 5)); // hilbert\n        raw.push_back(order_group_by_key(group, 4)); // morton\n        raw.push_back(order_group_by_key(group, 0)); // x\n        raw.push_back(order_group_by_key(group, 1)); // y\n        raw.push_back(order_group_by_key(group, 2)); // x+y\n        raw.push_back(order_group_by_key(group, 3)); // x-y\n        raw.push_back(mst_preorder_order(group));\n        raw.push_back(nearest_neighbor_order(group, 0));\n        raw.push_back(nearest_neighbor_order(group, 1));\n\n        vector<vector<int>> cands;\n        unordered_set<uint64_t> seen;\n        seen.reserve(raw.size() * 4);\n\n        auto add_ord = [&](const vector<int>& ord) {\n            uint64_t h = hash_vec_ordered(ord);\n            if (!seen.count(h)) {\n                seen.insert(h);\n                cands.push_back(ord);\n            }\n        };\n\n        for (auto &ord : raw) {\n            add_ord(ord);\n            add_ord(reversed_copy(ord));\n        }\n\n        double best_score = INF;\n        vector<int> best = group;\n        for (auto &ord : cands) {\n            double sc = approx_union_tree_cost_for_order(ord);\n            if (sc < best_score) {\n                best_score = sc;\n                best = ord;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> query(const vector<int>& cities) {\n        cout << \"? \" << cities.size();\n        for (int v : cities) cout << \" \" << v;\n        cout << endl;\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)cities.size() - 1);\n        for (int i = 0; i < (int)cities.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            ret.push_back(norm_edge(a, b));\n        }\n        used_queries++;\n        return ret;\n    }\n\n    struct ExtraWindow {\n        int start, len;\n        vector<uint64_t> approx_edges;\n        double sub_cost;\n        bool used = false;\n    };\n\n    struct GroupPlan {\n        vector<int> order;\n        vector<pair<int,int>> primary;\n        vector<ExtraWindow> extras;\n        unordered_set<uint64_t> current_approx_edges;\n        double current_approx_cost = 0.0;\n        int version = 0;\n    };\n\n    struct PQNode {\n        double gain;\n        double sub_cost;\n        int gid;\n        int extra_idx;\n        int version;\n        bool operator<(const PQNode& other) const {\n            if (fabs(gain - other.gain) > 1e-9) return gain < other.gain;\n            if (fabs(sub_cost - other.sub_cost) > 1e-9) return sub_cost < other.sub_cost;\n            if (gid != other.gid) return gid > other.gid;\n            return extra_idx > other.extra_idx;\n        }\n    };\n\n    pair<double, bool> evaluate_extra_gain(const GroupPlan& plan, const ExtraWindow& ew) {\n        unordered_set<uint64_t> merged = plan.current_approx_edges;\n        merged.reserve(plan.current_approx_edges.size() + ew.approx_edges.size() * 2 + 8);\n        bool adds_new = false;\n        for (auto k : ew.approx_edges) {\n            if (!merged.count(k)) adds_new = true;\n            merged.insert(k);\n        }\n        if (!adds_new) return {0.0, false};\n        double new_cost = completed_tree_cost_from_keys(plan.order, merged);\n        return {plan.current_approx_cost - new_cost, true};\n    }\n\n    void push_best_extra_for_group(priority_queue<PQNode>& pq, vector<GroupPlan>& plans, int gid) {\n        double best_gain = 0.0;\n        double best_sub = 0.0;\n        int best_idx = -1;\n        for (int i = 0; i < (int)plans[gid].extras.size(); i++) {\n            if (plans[gid].extras[i].used) continue;\n            auto [gain, ok] = evaluate_extra_gain(plans[gid], plans[gid].extras[i]);\n            if (!ok) continue;\n            if (gain > best_gain + 1e-9 ||\n                (fabs(gain - best_gain) <= 1e-9 && plans[gid].extras[i].sub_cost > best_sub)) {\n                best_gain = gain;\n                best_sub = plans[gid].extras[i].sub_cost;\n                best_idx = i;\n            }\n        }\n        if (best_idx != -1 && best_gain > 1e-9) {\n            pq.push({best_gain, best_sub, gid, best_idx, plans[gid].version});\n        }\n    }\n\n    vector<pair<int,int>> final_tree_from_edge_union(\n        const vector<int>& group,\n        const unordered_set<uint64_t>& exact_eset\n    ) {\n        int n = (int)group.size();\n        if (n <= 1) return {};\n\n        vector<pair<double, pair<int,int>>> exact_edges;\n        exact_edges.reserve(exact_eset.size());\n        for (auto key : exact_eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            exact_edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(exact_edges.begin(), exact_edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> ans;\n        ans.reserve(n - 1);\n\n        for (auto &e : exact_edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) {\n                ans.push_back({a, b});\n            }\n        }\n\n        unordered_map<int, int> comp_id;\n        comp_id.reserve(n * 2);\n        vector<int> roots;\n        for (int v : group) {\n            int r = dsu.find(v);\n            if (!comp_id.count(r)) {\n                int id = (int)roots.size();\n                comp_id[r] = id;\n                roots.push_back(r);\n            }\n        }\n        int cc = (int)roots.size();\n        if (cc <= 1) return ans;\n\n        struct CEdge {\n            double d;\n            int a, b;\n            int cu, cv;\n        };\n        vector<CEdge> cand;\n        cand.reserve((size_t)n * (n - 1) / 2);\n\n        for (int i = 0; i < n; i++) {\n            int u = group[i];\n            int cu = comp_id[dsu.find(u)];\n            for (int j = i + 1; j < n; j++) {\n                int v = group[j];\n                int cv = comp_id[dsu.find(v)];\n                if (cu == cv) continue;\n                cand.push_back({distm[u][v], u, v, cu, cv});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const CEdge& x, const CEdge& y) {\n            if (fabs(x.d - y.d) > 1e-9) return x.d < y.d;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        DSU comp_dsu(cc);\n        for (auto &e : cand) {\n            if (comp_dsu.unite(e.cu, e.cv)) {\n                ans.push_back(norm_edge(e.a, e.b));\n                if ((int)ans.size() == n - 1) break;\n            }\n        }\n\n        if ((int)ans.size() != n - 1) {\n            return approx_mst_edges_full(group);\n        }\n        return ans;\n    }\n\n    void solve() {\n        input();\n\n        auto groups = build_groups();\n\n        vector<GroupPlan> plans(M);\n        int primary_queries = 0;\n\n        for (int gid = 0; gid < M; gid++) {\n            plans[gid].order = choose_best_local_order(groups[gid]);\n            int n = (int)plans[gid].order.size();\n            plans[gid].primary = make_primary_windows_indices(n);\n            auto extra_idx = make_extra_windows_indices(n);\n            primary_queries += (int)plans[gid].primary.size();\n\n            plans[gid].current_approx_edges.reserve(max(8, n * 4));\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(plans[gid].order.begin() + s, plans[gid].order.begin() + s + len);\n                auto es = approx_mst_edges_small(w);\n                for (auto [a, b] : es) plans[gid].current_approx_edges.insert(edge_key(a, b));\n            }\n            plans[gid].current_approx_cost =\n                completed_tree_cost_from_keys(plans[gid].order, plans[gid].current_approx_edges);\n\n            for (auto [s, len] : extra_idx) {\n                vector<int> w(plans[gid].order.begin() + s, plans[gid].order.begin() + s + len);\n                auto es = approx_mst_edges_small(w);\n                vector<uint64_t> keys;\n                keys.reserve(es.size());\n                for (auto [a, b] : es) keys.push_back(edge_key(a, b));\n                double subc = mst_cost_of_list(w);\n                plans[gid].extras.push_back({s, len, move(keys), subc, false});\n            }\n        }\n\n        int remain = max(0, Q - primary_queries);\n\n        priority_queue<PQNode> pq;\n        for (int gid = 0; gid < M; gid++) {\n            push_best_extra_for_group(pq, plans, gid);\n        }\n\n        vector<vector<pair<int,int>>> chosen_extras(M);\n\n        while (remain > 0 && !pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.version != plans[cur.gid].version) continue;\n            if (plans[cur.gid].extras[cur.extra_idx].used) continue;\n\n            auto [gain, ok] = evaluate_extra_gain(plans[cur.gid], plans[cur.gid].extras[cur.extra_idx]);\n            if (!ok || gain + 1e-9 < cur.gain) {\n                push_best_extra_for_group(pq, plans, cur.gid);\n                continue;\n            }\n            if (gain <= 1e-9) break;\n\n            auto &ew = plans[cur.gid].extras[cur.extra_idx];\n            ew.used = true;\n            chosen_extras[cur.gid].push_back({ew.start, ew.len});\n            for (auto k : ew.approx_edges) plans[cur.gid].current_approx_edges.insert(k);\n            plans[cur.gid].current_approx_cost =\n                completed_tree_cost_from_keys(plans[cur.gid].order, plans[cur.gid].current_approx_edges);\n            plans[cur.gid].version++;\n            push_best_extra_for_group(pq, plans, cur.gid);\n            remain--;\n        }\n\n        vector<unordered_set<uint64_t>> edge_unions(M);\n        for (int i = 0; i < M; i++) edge_unions[i].reserve(max(8, (int)groups[i].size() * 4));\n\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : chosen_extras[gid]) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        vector<vector<pair<int,int>>> answer_edges(M);\n        for (int gid = 0; gid < M; gid++) {\n            answer_edges[gid] = final_tree_from_edge_union(plans[gid].order, edge_unions[gid]);\n        }\n\n        cout << \"!\" << endl;\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (int i = 0; i < (int)ord.size(); i++) {\n                if (i) cout << ' ';\n                cout << ord[i];\n            }\n            cout << '\\n';\n            for (auto [a, b] : answer_edges[gid]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int POS = N * N;          // 400\nstatic constexpr int NONE = POS;           // 400\nstatic constexpr int BNUM = POS + 1;       // 401\nstatic constexpr int STATES = POS * BNUM;  // 160400\n\nstatic constexpr int INF = 30000;\nstatic constexpr int MAXDIST = 2000; // enough for 40 targets on 20x20\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar dch[4] = {'U', 'D', 'L', 'R'};\n\ninline int sid1(int pos, int b) { return pos * BNUM + b; }\ninline int pos_of_1(int s) { return s / BNUM; }\ninline int block_of_1(int s) { return s % BNUM; }\ninline bool valid_state_1(int pos, int b) { return b == NONE || b != pos; }\n\nint neigh[POS][4];\nunsigned short slide_to_1[BNUM][POS][4];\nstatic vector<unsigned short> revSlide[BNUM][POS];\n\nvector<unsigned short> dist_all;\nstatic vector<int> buckets[MAXDIST + 1];\n\nstruct Action {\n    char a, d;\n};\n\ninline unsigned short* stage_ptr(int k) {\n    return dist_all.data() + (size_t)k * STATES;\n}\n\n// ---------- 2-block temporary model ----------\ninline void canon2(int &b1, int &b2) {\n    if (b1 == NONE) {\n        b2 = NONE;\n        return;\n    }\n    if (b2 == NONE) return;\n    if (b2 < b1) swap(b1, b2);\n}\n\ninline bool valid_state_2(int pos, int b1, int b2) {\n    if (b1 != NONE && b1 == pos) return false;\n    if (b2 != NONE && b2 == pos) return false;\n    return true;\n}\n\ninline int encode2(int pos, int b1, int b2) {\n    // phase-less code\n    return ((b1 * BNUM + b2) * POS + pos);\n}\n\ninline void decode2(int code, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    b1 = t / BNUM;\n}\n\ninline int encodeP(int phase, int pos, int b1, int b2) {\n    return ((((phase * BNUM) + b1) * BNUM + b2) * POS + pos);\n}\n\ninline void decodeP(int code, int &phase, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    t /= BNUM;\n    b1 = t % BNUM;\n    phase = t / BNUM;\n}\n\ninline int slide_to_2(int pos, int b1, int b2, int dir) {\n    int cur = pos;\n    while (true) {\n        int np = neigh[cur][dir];\n        if (np == -1) break;\n        if (np == b1 || np == b2) break;\n        cur = np;\n    }\n    return cur;\n}\n\nvoid precompute() {\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int p = r * N + c;\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                    neigh[p][d] = nr * N + nc;\n                } else {\n                    neigh[p][d] = -1;\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int p = 0; p < POS; p++) {\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; d++) {\n                int cr = r, cc = c;\n                while (true) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) break;\n                    int np = nr * N + nc;\n                    if (b != NONE && np == b) break;\n                    cr = nr;\n                    cc = nc;\n                }\n                slide_to_1[b][p][d] = (unsigned short)(cr * N + cc);\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int q = 0; q < POS; q++) {\n            if (!valid_state_1(q, b)) continue;\n            for (int d = 0; d < 4; d++) {\n                int p = slide_to_1[b][q][d];\n                if (p != q && valid_state_1(p, b)) {\n                    revSlide[b][p].push_back((unsigned short)q);\n                }\n            }\n        }\n    }\n}\n\nvoid compute_stage_dist(int k, const vector<int>& pts, int M) {\n    unsigned short* dist = stage_ptr(k);\n    for (int i = 0; i < STATES; i++) dist[i] = INF;\n    for (int i = 0; i <= MAXDIST; i++) buckets[i].clear();\n\n    int target_next = pts[k + 1];\n    unsigned short* next_dist = (k + 1 < M - 1 ? stage_ptr(k + 1) : nullptr);\n\n    int max_used = 0;\n\n    for (int b = 0; b < BNUM; b++) {\n        if (!valid_state_1(target_next, b)) continue;\n        int s = sid1(target_next, b);\n        unsigned short init_cost = (k + 1 == M - 1 ? 0 : next_dist[s]);\n        dist[s] = init_cost;\n        if (init_cost <= MAXDIST) {\n            buckets[init_cost].push_back(s);\n            max_used = max(max_used, (int)init_cost);\n        }\n    }\n\n    auto relax = [&](int ns, int nd) {\n        if (nd > MAXDIST) return;\n        if (nd < dist[ns]) {\n            dist[ns] = (unsigned short)nd;\n            buckets[nd].push_back(ns);\n            if (nd > max_used) max_used = nd;\n        }\n    };\n\n    for (int cd = 0; cd <= max_used; cd++) {\n        auto &bk = buckets[cd];\n        for (size_t it = 0; it < bk.size(); it++) {\n            int s = bk[it];\n            if (dist[s] != cd) continue;\n\n            int p = pos_of_1(s);\n            int b = block_of_1(s);\n            int nd = cd + 1;\n\n            // reverse of Move\n            for (int d = 0; d < 4; d++) {\n                int q = neigh[p][d];\n                if (q == -1) continue;\n                if (!valid_state_1(q, b)) continue;\n                relax(sid1(q, b), nd);\n            }\n\n            // reverse of Slide\n            for (unsigned short q : revSlide[b][p]) {\n                relax(sid1((int)q, b), nd);\n            }\n\n            // reverse of Alter\n            if (b == NONE) {\n                for (int d = 0; d < 4; d++) {\n                    int a = neigh[p][d];\n                    if (a == -1) continue;\n                    relax(sid1(p, a), nd);\n                }\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    if (neigh[p][d] == b) {\n                        relax(sid1(p, NONE), nd);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid reconstruct_baseline_segment(\n    int k,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    vector<Action>& seg,\n    int& end_block\n) {\n    seg.clear();\n    int target = pts[k + 1];\n    unsigned short* dist = stage_ptr(k);\n\n    int p = start_pos;\n    int b = start_block;\n    int curd = dist[sid1(p, b)];\n\n    while (p != target) {\n        bool found = false;\n\n        auto take = [&](char ac, int dir, int np, int nb) -> bool {\n            if (!valid_state_1(np, nb)) return false;\n            if (dist[sid1(np, nb)] + 1 != curd) return false;\n            seg.push_back({ac, dch[dir]});\n            p = np;\n            b = nb;\n            curd = dist[sid1(p, b)];\n            return true;\n        };\n\n        // prefer slide, then move, then alter\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int sp = slide_to_1[b][p][dir];\n            if (sp != p) found = take('S', dir, sp, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int np = neigh[p][dir];\n            if (np != -1 && np != b) found = take('M', dir, np, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n            if (b == NONE) found = take('A', dir, p, ap);\n            else if (b == ap) found = take('A', dir, p, NONE);\n        }\n\n        if (!found) break; // should not happen\n    }\n\n    end_block = b;\n}\n\nstruct TempNode {\n    int code;         // encoded (phase, pos, b1, b2)\n    int parent;\n    unsigned char op; // 0..11\n    unsigned short dist;\n};\n\n// horizon = 1 or 2\nbool try_improve_horizon(\n    int stage,\n    int horizon,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    int M,\n    int baseline_total,\n    const vector<int>& best_from_checkpoint,\n    vector<Action>& improved_seg,\n    int& improved_end_block\n) {\n    improved_seg.clear();\n    improved_end_block = start_block;\n\n    int end_idx = stage + horizon;\n    int min_future = best_from_checkpoint[end_idx];\n    int gmax = baseline_total - min_future - 1;\n    if (gmax <= 0) return false;\n\n    // Practical cap: enough to capture most useful local improvements\n    gmax = min(gmax, 40);\n\n    vector<TempNode> nodes;\n    nodes.reserve(50000);\n    vector<int> q;\n    q.reserve(50000);\n\n    unordered_map<int, int> id;\n    id.reserve(70000);\n    id.max_load_factor(0.7f);\n\n    auto push_state = [&](int code, int parent, unsigned char op, int nd) {\n        auto it = id.find(code);\n        if (it != id.end()) return;\n        int idx = (int)nodes.size();\n        id.emplace(code, idx);\n        nodes.push_back({code, parent, op, (unsigned short)nd});\n        q.push_back(idx);\n    };\n\n    int b1 = (start_block == NONE ? NONE : start_block);\n    int b2 = NONE;\n    int start_code = encodeP(0, start_pos, b1, b2);\n    push_state(start_code, -1, 255, 0);\n\n    int best_idx = -1;\n    int best_total = baseline_total;\n\n    for (size_t qi = 0; qi < q.size(); qi++) {\n        int idx = q[qi];\n        const auto &nd = nodes[idx];\n\n        int phase, p, x1, x2;\n        decodeP(nd.code, phase, p, x1, x2);\n\n        if (phase == horizon && x2 == NONE) {\n            int endb = x1;\n            int future = (end_idx == M - 1 ? 0 : stage_ptr(end_idx)[sid1(pts[end_idx], endb)]);\n            int total = nd.dist + future;\n            if (total < best_total) {\n                best_total = total;\n                best_idx = idx;\n            }\n        }\n\n        if (nd.dist >= gmax) continue;\n        if ((int)nodes.size() > 180000) break; // emergency cap\n\n        int nextd = nd.dist + 1;\n\n        auto advance_phase = [&](int cur_phase, char act, int np) -> int {\n            if (act == 'A') return cur_phase;\n            if (cur_phase < horizon && np == pts[stage + cur_phase + 1]) return cur_phase + 1;\n            return cur_phase;\n        };\n\n        // Move\n        for (int dir = 0; dir < 4; dir++) {\n            int np = neigh[p][dir];\n            if (np == -1) continue;\n            if (np == x1 || np == x2) continue;\n            int nphase = advance_phase(phase, 'M', np);\n            push_state(encodeP(nphase, np, x1, x2), idx, (unsigned char)(0 + dir), nextd);\n        }\n\n        // Slide\n        for (int dir = 0; dir < 4; dir++) {\n            int sp = slide_to_2(p, x1, x2, dir);\n            if (sp == p) continue;\n            int nphase = advance_phase(phase, 'S', sp);\n            push_state(encodeP(nphase, sp, x1, x2), idx, (unsigned char)(4 + dir), nextd);\n        }\n\n        // Alter\n        for (int dir = 0; dir < 4; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n\n            int nb1 = x1, nb2 = x2;\n\n            if (ap == x1) {\n                if (x2 == NONE) {\n                    nb1 = NONE;\n                    nb2 = NONE;\n                } else {\n                    nb1 = x2;\n                    nb2 = NONE;\n                }\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else if (ap == x2) {\n                nb2 = NONE;\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else {\n                if (x2 == NONE) {\n                    if (x1 == NONE) {\n                        nb1 = ap;\n                        nb2 = NONE;\n                    } else {\n                        nb1 = x1;\n                        nb2 = ap;\n                        canon2(nb1, nb2);\n                    }\n                    if (valid_state_2(p, nb1, nb2)) {\n                        push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n                    }\n                }\n            }\n        }\n    }\n\n    if (best_idx == -1) return false;\n\n    vector<unsigned char> ops;\n    int cur = best_idx;\n    while (nodes[cur].parent != -1) {\n        ops.push_back(nodes[cur].op);\n        cur = nodes[cur].parent;\n    }\n    reverse(ops.begin(), ops.end());\n\n    for (unsigned char op : ops) {\n        char a = (op < 4 ? 'M' : op < 8 ? 'S' : 'A');\n        char d = dch[op & 3];\n        improved_seg.push_back({a, d});\n    }\n\n    int phase, p, y1, y2;\n    decodeP(nodes[best_idx].code, phase, p, y1, y2);\n    improved_end_block = y1;\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    int Nin, M;\n    cin >> Nin >> M;\n    vector<int> pts(M);\n    for (int i = 0; i < M; i++) {\n        int r, c;\n        cin >> r >> c;\n        pts[i] = r * N + c;\n    }\n\n    if (M == 1) return 0;\n\n    dist_all.assign((size_t)(M - 1) * STATES, (unsigned short)INF);\n\n    for (int k = M - 2; k >= 0; k--) {\n        compute_stage_dist(k, pts, M);\n    }\n\n    // best_from_checkpoint[idx]:\n    // minimal remaining cost from position pts[idx] with 0/1 block state\n    // after target idx has just been visited.\n    vector<int> best_from_checkpoint(M, 0);\n    best_from_checkpoint[M - 1] = 0;\n    for (int idx = 1; idx <= M - 2; idx++) {\n        int best = INF;\n        unsigned short* dist = stage_ptr(idx);\n        for (int b = 0; b < BNUM; b++) {\n            if (!valid_state_1(pts[idx], b)) continue;\n            best = min(best, (int)dist[sid1(pts[idx], b)]);\n        }\n        best_from_checkpoint[idx] = best;\n    }\n\n    vector<Action> ans;\n    ans.reserve(1600);\n\n    int cur_pos = pts[0];\n    int cur_block = NONE;\n    int stage = 0;\n\n    while (stage < M - 1) {\n        int baseline_total = stage_ptr(stage)[sid1(cur_pos, cur_block)];\n\n        bool improved = false;\n        vector<Action> seg;\n        int end_block = NONE;\n\n        // First try 2-stage local search (spanning one target boundary)\n        if (stage + 2 <= M - 1) {\n            improved = try_improve_horizon(\n                stage, 2, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 2];\n                cur_block = end_block;\n                stage += 2;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // For the final single stage, try 1-stage temporary 2-block improvement\n        if (stage + 1 == M - 1) {\n            improved = try_improve_horizon(\n                stage, 1, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 1];\n                cur_block = end_block;\n                stage += 1;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // Fallback: exact 1-block baseline, one stage\n        vector<Action> base_seg;\n        int base_end_block = NONE;\n        reconstruct_baseline_segment(stage, cur_pos, cur_block, pts, base_seg, base_end_block);\n        for (auto &x : base_seg) ans.push_back(x);\n        cur_pos = pts[stage + 1];\n        cur_block = base_end_block;\n        stage += 1;\n\n        if ((int)ans.size() > 2 * N * M) break;\n    }\n\n    if ((int)ans.size() > 2 * N * M) {\n        ans.resize(2 * N * M);\n    }\n\n    for (auto &x : ans) {\n        cout << x.a << ' ' << x.d << '\\n';\n    }\n    return 0;\n}"},"16":{"ahc001":"#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 {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct State {\n    double score;\n    vector<Rect> rects;\n};\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr double TL = 4.95;\n\nint n;\nvector<int> X, Y;\nvector<long long> Rr;\n\nTimer timer;\nmt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ninline long long area(const Rect& r) {\n    return 1LL * (r.c - r.a) * (r.d - r.b);\n}\n\ninline double sat(long long s, long long r) {\n    double q = (double)min(s, r) / (double)max(s, r);\n    double t = 1.0 - q;\n    return 1.0 - t * t;\n}\n\ninline double local_score(const Rect& r, int i) {\n    return sat(area(r), Rr[i]);\n}\n\ndouble total_score(const vector<Rect>& rects) {\n    double res = 0.0;\n    for (int i = 0; i < n; ++i) res += local_score(rects[i], i);\n    return res;\n}\n\ninline bool hoverlap(const Rect& x, const Rect& y) {\n    return max(x.a, y.a) < min(x.c, y.c);\n}\n\ninline bool voverlap(const Rect& x, const Rect& y) {\n    return max(x.b, y.b) < min(x.d, y.d);\n}\n\nbool legal(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& r = rects[i];\n        if (!(0 <= r.a && r.a < r.c && r.c <= BOARD)) return false;\n        if (!(0 <= r.b && r.b < r.d && r.d <= BOARD)) return false;\n        if (!(r.a <= X[i] && X[i] < r.c)) return false;\n        if (!(r.b <= Y[i] && Y[i] < r.d)) return false;\n    }\n    for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n        if (hoverlap(rects[i], rects[j]) && voverlap(rects[i], rects[j])) return false;\n    }\n    return true;\n}\n\n// ============================================================\n// Initial construction by recursive guillotine partition\n// ============================================================\n\nstruct Cand {\n    long double cost;\n    bool vertical;\n    int k;\n    int cut;\n};\n\nvoid split_rec(const vector<int>& ids, int L, int R, int B, int T,\n               vector<Rect>& leaf_box, bool randomized_pick, long double shape_lambda) {\n    int m = (int)ids.size();\n    if (m == 1) {\n        leaf_box[ids[0]] = {L, B, R, T};\n        return;\n    }\n\n    long long sumR = 0;\n    for (int id : ids) sumR += Rr[id];\n\n    vector<int> sx = ids, sy = ids;\n    sort(sx.begin(), sx.end(), [&](int i, int j) {\n        if (X[i] != X[j]) return X[i] < X[j];\n        return Y[i] < Y[j];\n    });\n    sort(sy.begin(), sy.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    vector<Cand> cands;\n    cands.reserve(2 * (m - 1));\n\n    int W = R - L;\n    int H = T - B;\n\n    // Vertical cuts\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sx[k - 1]];\n            int minC = X[sx[k - 1]] + 1;\n            int maxC = X[sx[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)L + (long double)W * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int w1 = cut - L;\n            int w2 = R - cut;\n            if (w1 <= 0 || w2 <= 0) continue;\n\n            long double desiredW = (long double)W * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)w1 - desiredW) / (long double)W;\n\n            long double shape = fabsl(log((long double)w1 / (long double)H))\n                              + fabsl(log((long double)w2 / (long double)H));\n\n            cands.push_back({err + shape_lambda * shape, true, k, cut});\n        }\n    }\n\n    // Horizontal cuts\n    {\n        long long pref = 0;\n        for (int k = 1; k < m; ++k) {\n            pref += Rr[sy[k - 1]];\n            int minC = Y[sy[k - 1]] + 1;\n            int maxC = Y[sy[k]];\n            if (minC > maxC) continue;\n\n            long double ideal = (long double)B + (long double)H * (long double)pref / (long double)sumR;\n            int cut = (int)llround((double)ideal);\n            cut = max(minC, min(maxC, cut));\n\n            int h1 = cut - B;\n            int h2 = T - cut;\n            if (h1 <= 0 || h2 <= 0) continue;\n\n            long double desiredH = (long double)H * (long double)pref / (long double)sumR;\n            long double err = fabsl((long double)h1 - desiredH) / (long double)H;\n\n            long double shape = fabsl(log((long double)W / (long double)h1))\n                              + fabsl(log((long double)W / (long double)h2));\n\n            cands.push_back({err + shape_lambda * shape, false, k, cut});\n        }\n    }\n\n    if (cands.empty()) {\n        int k = m / 2;\n        int cut = max(X[sx[k - 1]] + 1, min(X[sx[k]], (L + R) / 2));\n        cut = max(L + 1, min(R - 1, cut));\n        vector<int> left(sx.begin(), sx.begin() + k);\n        vector<int> right(sx.begin() + k, sx.end());\n        split_rec(left, L, cut, B, T, leaf_box, randomized_pick, shape_lambda);\n        split_rec(right, cut, R, B, T, leaf_box, randomized_pick, shape_lambda);\n        return;\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Cand& p, const Cand& q) {\n        return p.cost < q.cost;\n    });\n\n    int pick = 0;\n    if (randomized_pick) {\n        int top = min<int>(6, cands.size());\n        vector<long long> w(top);\n        long long s = 0;\n        for (int i = 0; i < top; ++i) {\n            w[i] = top - i;\n            s += w[i];\n        }\n        long long z = (long long)(rng() % s);\n        int chosen = 0;\n        while (z >= w[chosen]) {\n            z -= w[chosen];\n            ++chosen;\n        }\n        pick = chosen;\n    }\n\n    Cand best = cands[pick];\n\n    if (best.vertical) {\n        vector<int> left(sx.begin(), sx.begin() + best.k);\n        vector<int> right(sx.begin() + best.k, sx.end());\n        split_rec(left, L, best.cut, B, T, leaf_box, randomized_pick, shape_lambda);\n        split_rec(right, best.cut, R, B, T, leaf_box, randomized_pick, shape_lambda);\n    } else {\n        vector<int> down(sy.begin(), sy.begin() + best.k);\n        vector<int> up(sy.begin() + best.k, sy.end());\n        split_rec(down, L, R, B, best.cut, leaf_box, randomized_pick, shape_lambda);\n        split_rec(up, L, R, best.cut, T, leaf_box, randomized_pick, shape_lambda);\n    }\n}\n\nRect place_inside_box(const Rect& box, int id) {\n    int W = box.c - box.a;\n    int H = box.d - box.b;\n    long long boxA = 1LL * W * H;\n    long long target = Rr[id];\n\n    if (boxA <= target) return box;\n\n    long long bestA = -1;\n    int bestW = 1, bestH = 1;\n    long long bestShape = (1LL << 60);\n\n    for (int w = 1; w <= W; ++w) {\n        long long h = min<long long>(H, target / w);\n        if (h <= 0) continue;\n        long long a = 1LL * w * h;\n        long long shp = llabs((long long)w - h);\n        if (a > bestA || (a == bestA && shp < bestShape)) {\n            bestA = a;\n            bestW = w;\n            bestH = (int)h;\n            bestShape = shp;\n        }\n    }\n\n    int loA = max(box.a, X[id] + 1 - bestW);\n    int hiA = min(X[id], box.c - bestW);\n    int a = clamp(X[id] - bestW / 2, loA, hiA);\n    int c = a + bestW;\n\n    int loB = max(box.b, Y[id] + 1 - bestH);\n    int hiB = min(Y[id], box.d - bestH);\n    int b = clamp(Y[id] - bestH / 2, loB, hiB);\n    int d = b + bestH;\n\n    return {a, b, c, d};\n}\n\nlong double lambda_from_mode(int mode) {\n    static const long double vals[] = {\n        0.0L, 0.0008L, 0.0015L, 0.0030L, 0.0050L\n    };\n    return vals[mode];\n}\n\nvector<Rect> build_solution_mode(int mode, bool randomized_pick) {\n    vector<int> ids(n);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<Rect> boxes(n);\n    split_rec(ids, 0, BOARD, 0, BOARD, boxes, randomized_pick, lambda_from_mode(mode));\n\n    vector<Rect> rects(n);\n    for (int i = 0; i < n; ++i) rects[i] = place_inside_box(boxes[i], i);\n    return rects;\n}\n\nvector<Rect> build_solution_random() {\n    int mode = (int)(rng() % 5);\n    return build_solution_mode(mode, true);\n}\n\n// ============================================================\n// Cheap side-wise local hill climbing\n// ============================================================\n\nstruct Op {\n    double gain = 0.0;\n    Rect nr;\n};\n\nvector<int> candidate_steps(long long diff, int dim, int tmax) {\n    vector<int> cand;\n    cand.reserve(20);\n    cand.push_back(1);\n    cand.push_back(tmax);\n\n    long double q = (long double)diff / (long double)dim;\n    long long f = (long long)floor((double)q);\n    long long c = (long long)ceil((double)q);\n    for (int d = -2; d <= 2; ++d) {\n        cand.push_back((int)(f + d));\n        cand.push_back((int)(c + d));\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    vector<int> res;\n    for (int t : cand) if (1 <= t && t <= tmax) res.push_back(t);\n    return res;\n}\n\nOp best_operation_for(int i, const vector<Rect>& rects) {\n    const Rect& curR = rects[i];\n    long long s = area(curR);\n    long long target = Rr[i];\n    double curSat = sat(s, target);\n\n    Op best;\n    best.nr = curR;\n\n    int w = curR.c - curR.a;\n    int h = curR.d - curR.b;\n\n    if (s < target) {\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].c <= curR.a) bound = max(bound, rects[j].c);\n            }\n            int tmax = curR.a - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (voverlap(curR, rects[j]) && rects[j].a >= curR.c) bound = min(bound, rects[j].a);\n            }\n            int tmax = bound - curR.c;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, h, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = 0;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].d <= curR.b) bound = max(bound, rects[j].d);\n            }\n            int tmax = curR.b - bound;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int bound = BOARD;\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (hoverlap(curR, rects[j]) && rects[j].b >= curR.d) bound = min(bound, rects[j].b);\n            }\n            int tmax = bound - curR.d;\n            if (tmax > 0) {\n                auto cand = candidate_steps(target - s, w, tmax);\n                for (int t : cand) {\n                    long long ns = s + 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    if (s > target) {\n        {\n            int tmax = X[i] - curR.a;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.a += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = curR.c - (X[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, h, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * h * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.c -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = Y[i] - curR.b;\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.b += t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n        {\n            int tmax = curR.d - (Y[i] + 1);\n            if (tmax > 0) {\n                auto cand = candidate_steps(s - target, w, tmax);\n                for (int t : cand) {\n                    long long ns = s - 1LL * w * t;\n                    double gain = sat(ns, target) - curSat;\n                    if (gain > best.gain + 1e-15) {\n                        Rect nr = curR;\n                        nr.d -= t;\n                        best = {gain, nr};\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid side_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) {\n            double sc = local_score(rects[i], i);\n            double noise = (double)(rng() & 1023) * 1e-12;\n            ord.push_back({sc + noise, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        for (auto [_, i] : ord) {\n            if (timer.elapsed() >= end_time) break;\n            while (timer.elapsed() < end_time) {\n                Op op = best_operation_for(i, rects);\n                if (op.gain <= 1e-15) break;\n                rects[i] = op.nr;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Moderate exact single-rectangle optimization\n// ============================================================\n\nRect exact_best_for(int i, const vector<Rect>& rects) {\n    const Rect& cur = rects[i];\n    const long long target = Rr[i];\n    const int px = X[i];\n    const int py = Y[i];\n\n    Rect best = cur;\n    double bestSc = local_score(cur, i);\n\n    auto upd = [&](const Rect& cand) {\n        double sc = local_score(cand, i);\n        if (sc > bestSc + 1e-15) {\n            bestSc = sc;\n            best = cand;\n        } else if (fabs(sc - bestSc) <= 1e-15) {\n            long long da = llabs(area(cand) - target);\n            long long db = llabs(area(best) - target);\n            if (da < db) best = cand;\n        }\n    };\n\n    auto try_width = [&](int b, int d, int left, int right) {\n        if (!(b <= py && py < d)) return;\n        int H = d - b;\n        int maxW = right - left;\n        if (H <= 0 || maxW <= 0) return;\n\n        vector<int> ws;\n        ws.reserve(16);\n        ws.push_back(1);\n        ws.push_back(maxW);\n        ws.push_back(cur.c - cur.a);\n\n        long double ideal = (long double)target / (long double)H;\n        long long f = (long long)floor((double)ideal);\n        long long c = (long long)ceil((double)ideal);\n        for (int dt = -2; dt <= 2; ++dt) {\n            ws.push_back((int)(f + dt));\n            ws.push_back((int)(c + dt));\n        }\n\n        sort(ws.begin(), ws.end());\n        ws.erase(unique(ws.begin(), ws.end()), ws.end());\n\n        for (int w : ws) {\n            if (w < 1 || w > maxW) continue;\n            int loA = max(left, px + 1 - w);\n            int hiA = min(px, right - w);\n            if (loA > hiA) continue;\n            int pref = cur.a;\n            if (pref < loA || pref > hiA) pref = px - w / 2;\n            int a = clamp(pref, loA, hiA);\n            upd(Rect{a, b, a + w, d});\n        }\n    };\n\n    auto try_height = [&](int a, int c, int bot, int top) {\n        if (!(a <= px && px < c)) return;\n        int W = c - a;\n        int maxH = top - bot;\n        if (W <= 0 || maxH <= 0) return;\n\n        vector<int> hs;\n        hs.reserve(16);\n        hs.push_back(1);\n        hs.push_back(maxH);\n        hs.push_back(cur.d - cur.b);\n\n        long double ideal = (long double)target / (long double)W;\n        long long f = (long long)floor((double)ideal);\n        long long cc = (long long)ceil((double)ideal);\n        for (int dt = -2; dt <= 2; ++dt) {\n            hs.push_back((int)(f + dt));\n            hs.push_back((int)(cc + dt));\n        }\n\n        sort(hs.begin(), hs.end());\n        hs.erase(unique(hs.begin(), hs.end()), hs.end());\n\n        for (int h : hs) {\n            if (h < 1 || h > maxH) continue;\n            int loB = max(bot, py + 1 - h);\n            int hiB = min(py, top - h);\n            if (loB > hiB) continue;\n            int pref = cur.b;\n            if (pref < loB || pref > hiB) pref = py - h / 2;\n            int b = clamp(pref, loB, hiB);\n            upd(Rect{a, b, c, b + h});\n        }\n    };\n\n    {\n        vector<int> bottoms, tops;\n        bottoms.reserve(n + 8);\n        tops.reserve(n + 8);\n\n        bottoms.push_back(0);\n        bottoms.push_back(py);\n        bottoms.push_back(cur.b);\n\n        tops.push_back(BOARD);\n        tops.push_back(py + 1);\n        tops.push_back(cur.d);\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            if (rects[j].d <= py) bottoms.push_back(rects[j].d);\n            if (rects[j].b > py) tops.push_back(rects[j].b);\n        }\n\n        sort(bottoms.begin(), bottoms.end());\n        bottoms.erase(unique(bottoms.begin(), bottoms.end()), bottoms.end());\n        sort(tops.begin(), tops.end());\n        tops.erase(unique(tops.begin(), tops.end()), tops.end());\n\n        for (int b : bottoms) {\n            if (b > py) continue;\n            for (int d : tops) {\n                if (d <= py || b >= d) continue;\n\n                int left = 0, right = BOARD;\n                bool bad = false;\n\n                for (int j = 0; j < n; ++j) if (j != i) {\n                    const Rect& o = rects[j];\n                    if (o.d <= b || d <= o.b) continue;\n                    if (o.a <= px && px < o.c) {\n                        bad = true;\n                        break;\n                    }\n                    if (o.c <= px) left = max(left, o.c);\n                    else if (o.a > px) right = min(right, o.a);\n                }\n                if (bad || left >= right) continue;\n\n                try_width(b, d, left, right);\n            }\n        }\n    }\n\n    {\n        vector<int> lefts, rights;\n        lefts.reserve(n + 8);\n        rights.reserve(n + 8);\n\n        lefts.push_back(0);\n        lefts.push_back(px);\n        lefts.push_back(cur.a);\n\n        rights.push_back(BOARD);\n        rights.push_back(px + 1);\n        rights.push_back(cur.c);\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            if (rects[j].c <= px) lefts.push_back(rects[j].c);\n            if (rects[j].a > px) rights.push_back(rects[j].a);\n        }\n\n        sort(lefts.begin(), lefts.end());\n        lefts.erase(unique(lefts.begin(), lefts.end()), lefts.end());\n        sort(rights.begin(), rights.end());\n        rights.erase(unique(rights.begin(), rights.end()), rights.end());\n\n        for (int a : lefts) {\n            if (a > px) continue;\n            for (int c : rights) {\n                if (c <= px || a >= c) continue;\n\n                int bot = 0, top = BOARD;\n                bool bad = false;\n\n                for (int j = 0; j < n; ++j) if (j != i) {\n                    const Rect& o = rects[j];\n                    if (o.c <= a || c <= o.a) continue;\n                    if (o.b <= py && py < o.d) {\n                        bad = true;\n                        break;\n                    }\n                    if (o.d <= py) bot = max(bot, o.d);\n                    else if (o.b > py) top = min(top, o.b);\n                }\n                if (bad || bot >= top) continue;\n\n                try_height(a, c, bot, top);\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid exact_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        vector<pair<double,int>> ord;\n        ord.reserve(n);\n        for (int i = 0; i < n; ++i) ord.push_back({local_score(rects[i], i), i});\n        sort(ord.begin(), ord.end());\n\n        bool changed = false;\n        int K = min(n, (n <= 80 ? 12 : n <= 130 ? 10 : 8));\n\n        for (int z = 0; z < K; ++z) {\n            if (timer.elapsed() >= end_time) break;\n            int i = ord[z].second;\n\n            Rect nr = exact_best_for(i, rects);\n            if (local_score(nr, i) > local_score(rects[i], i) + 1e-15) {\n                rects[i] = nr;\n                changed = true;\n\n                while (timer.elapsed() < end_time) {\n                    Op op = best_operation_for(i, rects);\n                    if (op.gain <= 1e-15) break;\n                    rects[i] = op.nr;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\n// ============================================================\n// Pairwise cut optimization for clean adjacent pairs\n// ============================================================\n\nstruct PairMove {\n    double gain = 0.0;\n    int i = -1, j = -1;\n    Rect ri, rj;\n};\n\nvector<int> around_candidates(long long v, int lo, int hi) {\n    vector<int> res;\n    for (int d = -3; d <= 3; ++d) {\n        long long x = v + d;\n        if (lo <= x && x <= hi) res.push_back((int)x);\n    }\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nPairMove best_pair_move(const vector<Rect>& rects) {\n    PairMove best;\n\n    for (int i = 0; i < n; ++i) for (int j = i + 1; j < n; ++j) {\n        const Rect& A = rects[i];\n        const Rect& B = rects[j];\n\n        if (A.b == B.b && A.d == B.d && (A.c == B.a || B.c == A.a)) {\n            int l = i, r = j;\n            Rect RL = A, RR = B;\n            if (RL.a > RR.a) {\n                swap(l, r);\n                swap(RL, RR);\n            }\n\n            int L = RL.a, R = RR.c, Btm = RL.b, Top = RL.d;\n            int H = Top - Btm;\n            if (H > 0) {\n                int lo = max(L + 1, X[l] + 1);\n                int hi = min(R - 1, X[r]);\n                if (lo <= hi) {\n                    double cur = local_score(RL, l) + local_score(RR, r);\n                    vector<int> cand = {lo, hi, RL.c};\n\n                    long long w1f = Rr[l] / H;\n                    long long w1c = (Rr[l] + H - 1) / H;\n                    long long cut1 = L + w1f;\n                    long long cut2 = L + w1c;\n                    auto v1 = around_candidates(cut1, lo, hi);\n                    auto v2 = around_candidates(cut2, lo, hi);\n                    cand.insert(cand.end(), v1.begin(), v1.end());\n                    cand.insert(cand.end(), v2.begin(), v2.end());\n\n                    long long w2f = Rr[r] / H;\n                    long long w2c = (Rr[r] + H - 1) / H;\n                    long long cut3 = R - w2f;\n                    long long cut4 = R - w2c;\n                    auto v3 = around_candidates(cut3, lo, hi);\n                    auto v4 = around_candidates(cut4, lo, hi);\n                    cand.insert(cand.end(), v3.begin(), v3.end());\n                    cand.insert(cand.end(), v4.begin(), v4.end());\n\n                    sort(cand.begin(), cand.end());\n                    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n                    for (int cut : cand) {\n                        Rect nL{L, Btm, cut, Top};\n                        Rect nR{cut, Btm, R, Top};\n                        double nxt = local_score(nL, l) + local_score(nR, r);\n                        double gain = nxt - cur;\n                        if (gain > best.gain + 1e-15) {\n                            best.gain = gain;\n                            best.i = l;\n                            best.j = r;\n                            best.ri = nL;\n                            best.rj = nR;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (A.a == B.a && A.c == B.c && (A.d == B.b || B.d == A.b)) {\n            int dwn = i, up = j;\n            Rect RD = A, RU = B;\n            if (RD.b > RU.b) {\n                swap(dwn, up);\n                swap(RD, RU);\n            }\n\n            int L = RD.a, R = RD.c, Btm = RD.b, Top = RU.d;\n            int W = R - L;\n            if (W > 0) {\n                int lo = max(Btm + 1, Y[dwn] + 1);\n                int hi = min(Top - 1, Y[up]);\n                if (lo <= hi) {\n                    double cur = local_score(RD, dwn) + local_score(RU, up);\n                    vector<int> cand = {lo, hi, RD.d};\n\n                    long long h1f = Rr[dwn] / W;\n                    long long h1c = (Rr[dwn] + W - 1) / W;\n                    long long cut1 = Btm + h1f;\n                    long long cut2 = Btm + h1c;\n                    auto v1 = around_candidates(cut1, lo, hi);\n                    auto v2 = around_candidates(cut2, lo, hi);\n                    cand.insert(cand.end(), v1.begin(), v1.end());\n                    cand.insert(cand.end(), v2.begin(), v2.end());\n\n                    long long h2f = Rr[up] / W;\n                    long long h2c = (Rr[up] + W - 1) / W;\n                    long long cut3 = Top - h2f;\n                    long long cut4 = Top - h2c;\n                    auto v3 = around_candidates(cut3, lo, hi);\n                    auto v4 = around_candidates(cut4, lo, hi);\n                    cand.insert(cand.end(), v3.begin(), v3.end());\n                    cand.insert(cand.end(), v4.begin(), v4.end());\n\n                    sort(cand.begin(), cand.end());\n                    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n                    for (int cut : cand) {\n                        Rect nD{L, Btm, R, cut};\n                        Rect nU{L, cut, R, Top};\n                        double nxt = local_score(nD, dwn) + local_score(nU, up);\n                        double gain = nxt - cur;\n                        if (gain > best.gain + 1e-15) {\n                            best.gain = gain;\n                            best.i = dwn;\n                            best.j = up;\n                            best.ri = nD;\n                            best.rj = nU;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid pairwise_improve(vector<Rect>& rects, double end_time) {\n    while (timer.elapsed() < end_time) {\n        PairMove mv = best_pair_move(rects);\n        if (mv.gain <= 1e-15) break;\n\n        rects[mv.i] = mv.ri;\n        rects[mv.j] = mv.rj;\n\n        while (timer.elapsed() < end_time) {\n            Op op = best_operation_for(mv.i, rects);\n            if (op.gain <= 1e-15) break;\n            rects[mv.i] = op.nr;\n        }\n        while (timer.elapsed() < end_time) {\n            Op op = best_operation_for(mv.j, rects);\n            if (op.gain <= 1e-15) break;\n            rects[mv.j] = op.nr;\n        }\n    }\n}\n\nvoid add_state(vector<State>& states, vector<Rect> rects) {\n    if (!legal(rects)) return;\n    double sc = total_score(rects);\n    states.push_back({sc, std::move(rects)});\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)states.size() > 5) states.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    X.resize(n);\n    Y.resize(n);\n    Rr.resize(n);\n    for (int i = 0; i < n; ++i) {\n        cin >> X[i] >> Y[i] >> Rr[i];\n    }\n\n    vector<State> states;\n\n    vector<Rect> safe_baseline = build_solution_mode(2, false);\n    if (!legal(safe_baseline)) {\n        safe_baseline.resize(n);\n        for (int i = 0; i < n; ++i) safe_baseline[i] = {X[i], Y[i], X[i] + 1, Y[i] + 1};\n    }\n\n    // Deterministic diverse seeds\n    add_state(states, safe_baseline);\n    add_state(states, build_solution_mode(0, false));\n    add_state(states, build_solution_mode(4, false));\n\n    // Randomized diversified seeds\n    double init_end = 0.95;\n    while (timer.elapsed() < init_end) {\n        add_state(states, build_solution_random());\n    }\n\n    // Polish a few best states\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    int polish_cnt = min<int>(4, states.size());\n\n    double polish_end = 2.20;\n    for (int i = 0; i < polish_cnt; ++i) {\n        double now = timer.elapsed();\n        if (now >= polish_end) break;\n        double slice = (polish_end - now) / (double)(polish_cnt - i);\n        side_improve(states[i].rects, now + slice);\n        if (!legal(states[i].rects)) states[i].rects = safe_baseline;\n        states[i].score = total_score(states[i].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    int finalists = min<int>((n <= 100 ? 3 : 2), states.size());\n\n    double exact_end = 3.75;\n    for (int k = 0; k < finalists; ++k) {\n        double now = timer.elapsed();\n        if (now >= exact_end) break;\n        double slice = (exact_end - now) / (double)(finalists - k);\n        exact_improve(states[k].rects, now + slice);\n        if (!legal(states[k].rects)) states[k].rects = safe_baseline;\n        states[k].score = total_score(states[k].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    double pair_end = 4.45;\n    for (int k = 0; k < finalists; ++k) {\n        double now = timer.elapsed();\n        if (now >= pair_end) break;\n        double slice = (pair_end - now) / (double)(finalists - k);\n        pairwise_improve(states[k].rects, now + slice);\n        if (!legal(states[k].rects)) states[k].rects = safe_baseline;\n        states[k].score = total_score(states[k].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    // Short post-pairwise exact on top 2 before final selection\n    int post_cnt = min<int>(2, states.size());\n    double post_end = 4.82;\n    for (int k = 0; k < post_cnt; ++k) {\n        double now = timer.elapsed();\n        if (now >= post_end) break;\n        double slice = (post_end - now) / (double)(post_cnt - k);\n        exact_improve(states[k].rects, now + slice);\n        if (!legal(states[k].rects)) states[k].rects = safe_baseline;\n        states[k].score = total_score(states[k].rects);\n    }\n\n    sort(states.begin(), states.end(), [&](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<Rect> best = states[0].rects;\n    side_improve(best, TL);\n\n    if (!legal(best)) {\n        bool found = false;\n        for (auto& st : states) {\n            if (legal(st.rects)) {\n                best = st.rects;\n                found = true;\n                break;\n            }\n        }\n        if (!found) best = safe_baseline;\n    }\n\n    for (int i = 0; i < n; ++i) {\n        cout << best[i].a << ' ' << best[i].b << ' ' << best[i].c << ' ' << best[i].d << '\\n';\n    }\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int C = N * N;\n    static constexpr int FORCE_CAP = 16;\n    static constexpr int ELITE_MAX = 8;\n    static constexpr double TL = 1.92;\n\n    int si, sj, start;\n    array<int, C> tile{};\n    array<int, C> val{};\n    array<array<int, 4>, C> adj{};\n    array<uint8_t, C> deg{};\n\n    int M = 0;\n\n    vector<int> tileSize;\n    vector<int> tileSum;\n    vector<int> tileMax;\n    vector<int> tileExp2;\n    vector<int> tileUB;\n\n    vector<unsigned char> vis;\n\n    vector<int> cellSeen;\n    vector<int> cellComp;\n    vector<int> tileSeen;\n    int evalStamp = 1;\n    int tileStamp = 1;\n\n    array<int, C> qbuf{};\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n\n    struct Params {\n        int wExp2;\n        int wUb;\n        int wTiles;\n        int wImm;\n        int wBranches;\n        int wDeg;\n        double q;\n        int exactLimit;\n        int exactNodeLimit;\n    };\n\n    struct ReachInfo {\n        int selExp2 = 0;\n        int selUb = 0;\n        int selTiles = 0;\n        int maxUb = 0;\n        int maxTiles = 0;\n        int branches = 0;\n        int availDeg = 0;\n    };\n\n    struct Cand {\n        int to = -1;\n        int eval = 0;\n        int imm = 0;\n        int exp2 = 0;\n        int ub = 0;\n        int tiles = 0;\n        int branches = 0;\n        int availDeg = 0;\n\n        int endCell = -1;\n        uint8_t plen = 0;\n        array<int, FORCE_CAP> path{};\n    };\n\n    struct Solution {\n        vector<int> seq;\n        vector<int> pref;\n        vector<int> decisionPos;\n        int score = 0;\n        uint64_t hash = 0;\n    };\n\n    struct Built {\n        vector<int> seq;\n        vector<int> decisionPos;\n        int score = 0;\n    };\n\n    vector<Solution> elite;\n    Solution bestSol;\n\n    vector<int> exactBestPath;\n    vector<int> exactCurPath;\n    int exactBestScore = 0;\n    bool exactAbort = false;\n    int exactNodes = 0;\n    int exactNodeLimitNow = 0;\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int r, int c) const { return r * N + c; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    template <class Used>\n    inline int list_legal(int cur, const Used& used, int out[4]) const {\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            if (!used[tile[nx]]) out[cc++] = nx;\n        }\n        return cc;\n    }\n\n    void read_input() {\n        cin >> si >> sj;\n        start = id(si, sj);\n\n        int mxTile = -1;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int t;\n                cin >> t;\n                tile[id(r, c)] = t;\n                mxTile = max(mxTile, t);\n            }\n        }\n        M = mxTile + 1;\n\n        tileSize.assign(M, 0);\n        tileSum.assign(M, 0);\n        tileMax.assign(M, 0);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p;\n                cin >> p;\n                int v = id(r, c);\n                val[v] = p;\n                int t = tile[v];\n                tileSize[t]++;\n                tileSum[t] += p;\n                tileMax[t] = max(tileMax[t], p);\n            }\n        }\n\n        tileExp2.assign(M, 0);\n        tileUB.assign(M, 0);\n        for (int t = 0; t < M; t++) {\n            if (tileSize[t] == 1) {\n                tileExp2[t] = tileSum[t] * 2;\n                tileUB[t] = tileSum[t];\n            } else {\n                tileExp2[t] = tileSum[t];\n                tileUB[t] = tileMax[t];\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                int d = 0;\n                static const int dr[4] = {-1, 1, 0, 0};\n                static const int dc[4] = {0, 0, -1, 1};\n                for (int k = 0; k < 4; k++) {\n                    int nr = r + dr[k], nc = c + dc[k];\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                    int u = id(nr, nc);\n                    if (tile[u] == tile[v]) continue;\n                    adj[v][d++] = u;\n                }\n                deg[v] = (uint8_t)d;\n            }\n        }\n\n        vis.assign(M, 0);\n        cellSeen.assign(C, 0);\n        cellComp.assign(C, -1);\n        tileSeen.assign(M, 0);\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : seq) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    static bool cand_cmp(const Cand& a, const Cand& b) {\n        if (a.eval != b.eval) return a.eval > b.eval;\n        if (a.tiles != b.tiles) return a.tiles > b.tiles;\n        if (a.exp2 != b.exp2) return a.exp2 > b.exp2;\n        if (a.imm != b.imm) return a.imm > b.imm;\n        if (a.branches != b.branches) return a.branches > b.branches;\n        return a.availDeg > b.availDeg;\n    }\n\n    Params sample_params() {\n        static const Params presets[] = {\n            {6, 2, 90, 18, 45, 14, 0.08, 22, 32000},\n            {7, 2, 80, 20, 35, 18, 0.10, 22, 32000},\n            {6, 1, 110, 16, 55, 12, 0.12, 21, 30000},\n            {7, 3, 70, 22, 28, 20, 0.07, 20, 26000},\n            {5, 2, 120, 15, 60, 10, 0.14, 20, 24000},\n            {8, 1, 60, 24, 24, 22, 0.06, 18, 20000},\n        };\n        Params p = presets[rng.next_int(0, (int)(sizeof(presets) / sizeof(presets[0])) - 1)];\n\n        if (rng.next_double() < 0.5) p.q *= (0.92 + 0.16 * rng.next_double());\n\n        double e = elapsed();\n        if (e > 0.70) {\n            p.exactLimit = min(p.exactLimit, 20);\n            p.exactNodeLimit = min(p.exactNodeLimit, 22000);\n        }\n        if (e > 1.30) {\n            p.exactLimit = min(p.exactLimit, 18);\n            p.exactNodeLimit = min(p.exactNodeLimit, 14000);\n        }\n        return p;\n    }\n\n    inline int comp_metric(int exp2, int ub, int tiles, const Params& par) const {\n        return par.wExp2 * exp2 + par.wUb * ub + par.wTiles * tiles;\n    }\n\n    ReachInfo analyze_from_cell(int cell, const vector<unsigned char>& used, int forbidTile, const Params& par) {\n        ++evalStamp;\n\n        int compExp2[4];\n        int compUb[4];\n        int compTiles[4];\n        int compCnt = 0;\n\n        int branchIds[4];\n        int branchCnt = 0;\n\n        ReachInfo res;\n        int bestMetric = -1;\n\n        for (int i = 0; i < deg[cell]; i++) {\n            int s = adj[cell][i];\n            int ts = tile[s];\n            if (used[ts] || ts == forbidTile) continue;\n\n            res.availDeg++;\n\n            if (cellSeen[s] != evalStamp) {\n                int cid = compCnt++;\n                int qh = 0, qt = 0;\n                qbuf[qt++] = s;\n                cellSeen[s] = evalStamp;\n                cellComp[s] = cid;\n\n                ++tileStamp;\n                int exp2 = 0, ub = 0, tilesCnt = 0;\n\n                while (qh < qt) {\n                    int v = qbuf[qh++];\n                    int tv = tile[v];\n                    if (tileSeen[tv] != tileStamp) {\n                        tileSeen[tv] = tileStamp;\n                        exp2 += tileExp2[tv];\n                        ub += tileUB[tv];\n                        tilesCnt++;\n                    }\n                    for (int j = 0; j < deg[v]; j++) {\n                        int u = adj[v][j];\n                        int tu = tile[u];\n                        if (used[tu] || tu == forbidTile) continue;\n                        if (cellSeen[u] == evalStamp) continue;\n                        cellSeen[u] = evalStamp;\n                        cellComp[u] = cid;\n                        qbuf[qt++] = u;\n                    }\n                }\n\n                compExp2[cid] = exp2;\n                compUb[cid] = ub;\n                compTiles[cid] = tilesCnt;\n            }\n\n            int cid = cellComp[s];\n            int metric = comp_metric(compExp2[cid], compUb[cid], compTiles[cid], par);\n            if (metric > bestMetric ||\n                (metric == bestMetric && compTiles[cid] > res.selTiles) ||\n                (metric == bestMetric && compTiles[cid] == res.selTiles && compUb[cid] > res.selUb)) {\n                bestMetric = metric;\n                res.selExp2 = compExp2[cid];\n                res.selUb = compUb[cid];\n                res.selTiles = compTiles[cid];\n            }\n\n            res.maxUb = max(res.maxUb, compUb[cid]);\n            res.maxTiles = max(res.maxTiles, compTiles[cid]);\n\n            bool exists = false;\n            for (int b = 0; b < branchCnt; b++) {\n                if (branchIds[b] == cid) {\n                    exists = true;\n                    break;\n                }\n            }\n            if (!exists) branchIds[branchCnt++] = cid;\n        }\n\n        res.branches = branchCnt;\n        return res;\n    }\n\n    inline int candidate_eval(int gain, const ReachInfo& ri, const Params& par) const {\n        return par.wImm * gain\n             + par.wExp2 * ri.selExp2\n             + par.wUb * ri.selUb\n             + par.wTiles * ri.selTiles\n             + par.wBranches * ri.branches\n             + par.wDeg * ri.availDeg;\n    }\n\n    Cand build_macro_candidate(int first, vector<unsigned char>& used, const Params& par) {\n        Cand c;\n        c.to = first;\n\n        int marked[FORCE_CAP];\n        int mc = 0;\n\n        int cur = first;\n        while (true) {\n            int t = tile[cur];\n            used[t] = 1;\n            marked[mc++] = t;\n            c.path[c.plen++] = cur;\n            c.imm += val[cur];\n\n            if (c.plen >= FORCE_CAP) {\n                ReachInfo ri = analyze_from_cell(cur, used, -1, par);\n                c.exp2 = ri.selExp2;\n                c.ub = ri.selUb;\n                c.tiles = ri.selTiles;\n                c.branches = ri.branches;\n                c.availDeg = ri.availDeg;\n                c.endCell = cur;\n                c.eval = candidate_eval(c.imm, ri, par);\n                break;\n            }\n\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n            if (cc == 1) {\n                cur = nxts[0];\n                continue;\n            } else if (cc == 0) {\n                c.endCell = cur;\n                c.eval = par.wImm * c.imm;\n                break;\n            } else {\n                ReachInfo ri = analyze_from_cell(cur, used, -1, par);\n                c.exp2 = ri.selExp2;\n                c.ub = ri.selUb;\n                c.tiles = ri.selTiles;\n                c.branches = ri.branches;\n                c.availDeg = ri.availDeg;\n                c.endCell = cur;\n                c.eval = candidate_eval(c.imm, ri, par);\n                break;\n            }\n        }\n\n        for (int i = 0; i < mc; i++) used[marked[i]] = 0;\n        return c;\n    }\n\n    inline void add_decision_pos(vector<int>& dps, int pos) {\n        if (dps.empty() || dps.back() != pos) dps.push_back(pos);\n    }\n\n    void apply_macro(const Cand& c, Built& out) {\n        for (int i = 0; i < c.plen; i++) {\n            int v = c.path[i];\n            vis[tile[v]] = 1;\n            out.seq.push_back(v);\n            out.score += val[v];\n        }\n    }\n\n    void append_exact_suffix_with_decisions(Built& out, int cur, const vector<int>& suf) {\n        vector<unsigned char> used2 = vis;\n        int cur2 = cur;\n\n        for (int nx : suf) {\n            int nxts[4];\n            int cc = list_legal(cur2, used2, nxts);\n            if (cc >= 2) add_decision_pos(out.decisionPos, (int)out.seq.size() - 1);\n\n            used2[tile[nx]] = 1;\n            vis[tile[nx]] = 1;\n            out.seq.push_back(nx);\n            out.score += val[nx];\n            cur2 = nx;\n        }\n    }\n\n    vector<int> greedy_suffix_small(int cur, vector<unsigned char> used, const Params& par, int& outScore) {\n        vector<int> path;\n        outScore = 0;\n\n        while (true) {\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n            if (cc == 0) break;\n\n            if (cc == 1) {\n                int nx = nxts[0];\n                used[tile[nx]] = 1;\n                path.push_back(nx);\n                outScore += val[nx];\n                cur = nx;\n                continue;\n            }\n\n            Cand cs[4];\n            for (int i = 0; i < cc; i++) cs[i] = build_macro_candidate(nxts[i], used, par);\n            sort(cs, cs + cc, cand_cmp);\n\n            for (int i = 0; i < cs[0].plen; i++) {\n                int v = cs[0].path[i];\n                used[tile[v]] = 1;\n                path.push_back(v);\n                outScore += val[v];\n                cur = v;\n            }\n        }\n        return path;\n    }\n\n    void exact_dfs(int cur, vector<unsigned char>& used, int curScore, const Params& par) {\n        int forcedAdded = 0;\n\n        while (true) {\n            int nxts[4];\n            int cc = list_legal(cur, used, nxts);\n\n            if (cc == 0) {\n                if (curScore > exactBestScore) {\n                    exactBestScore = curScore;\n                    exactBestPath = exactCurPath;\n                }\n                for (int k = 0; k < forcedAdded; k++) {\n                    used[tile[exactCurPath.back()]] = 0;\n                    exactCurPath.pop_back();\n                }\n                return;\n            }\n            if (cc >= 2) break;\n\n            int nx = nxts[0];\n            used[tile[nx]] = 1;\n            exactCurPath.push_back(nx);\n            curScore += val[nx];\n            cur = nx;\n            forcedAdded++;\n        }\n\n        if ((++exactNodes & 255) == 0) {\n            if (exactNodes > exactNodeLimitNow || elapsed() > TL) {\n                exactAbort = true;\n                for (int k = 0; k < forcedAdded; k++) {\n                    used[tile[exactCurPath.back()]] = 0;\n                    exactCurPath.pop_back();\n                }\n                return;\n            }\n        }\n\n        ReachInfo ub = analyze_from_cell(cur, used, -1, par);\n        if (curScore + ub.maxUb <= exactBestScore) {\n            for (int k = 0; k < forcedAdded; k++) {\n                used[tile[exactCurPath.back()]] = 0;\n                exactCurPath.pop_back();\n            }\n            return;\n        }\n\n        Cand cs[4];\n        int cc = 0;\n        for (int i = 0; i < deg[cur]; i++) {\n            int nx = adj[cur][i];\n            int tnx = tile[nx];\n            if (used[tnx]) continue;\n            ReachInfo ri = analyze_from_cell(nx, used, tnx, par);\n            int ev = candidate_eval(val[nx], ri, par);\n            cs[cc++] = Cand{nx, ev, val[nx], ri.selExp2, ri.selUb, ri.selTiles, ri.branches, ri.availDeg};\n        }\n\n        if (cc > 1) sort(cs, cs + cc, cand_cmp);\n\n        for (int i = 0; i < cc; i++) {\n            int nx = cs[i].to;\n            int tnx = tile[nx];\n            used[tnx] = 1;\n            exactCurPath.push_back(nx);\n            exact_dfs(nx, used, curScore + val[nx], par);\n            exactCurPath.pop_back();\n            used[tnx] = 0;\n            if (exactAbort) break;\n        }\n\n        for (int k = 0; k < forcedAdded; k++) {\n            used[tile[exactCurPath.back()]] = 0;\n            exactCurPath.pop_back();\n        }\n    }\n\n    vector<int> exact_finish(int cur, vector<unsigned char>& used, const Params& par) {\n        exactBestPath.clear();\n        exactCurPath.clear();\n        exactBestScore = 0;\n        exactAbort = false;\n        exactNodes = 0;\n        exactNodeLimitNow = par.exactNodeLimit;\n\n        int greedyScore = 0;\n        exactBestPath = greedy_suffix_small(cur, used, par, greedyScore);\n        exactBestScore = greedyScore;\n\n        exact_dfs(cur, used, 0, par);\n        return exactBestPath;\n    }\n\n    void build_prefix_state(const Solution& base, int cutIdx, Built& out) {\n        fill(vis.begin(), vis.end(), 0);\n        out.seq.clear();\n        out.decisionPos.clear();\n        out.seq.reserve(C);\n\n        for (int i = 0; i <= cutIdx; i++) {\n            int v = base.seq[i];\n            out.seq.push_back(v);\n            vis[tile[v]] = 1;\n        }\n        out.score = base.pref[cutIdx];\n\n        for (int x : base.decisionPos) {\n            if (x <= cutIdx) out.decisionPos.push_back(x);\n            else break;\n        }\n    }\n\n    Built grow_from(const Solution& base, int cutIdx, const Params& par) {\n        Built out;\n        build_prefix_state(base, cutIdx, out);\n\n        int cur = out.seq.back();\n\n        while (true) {\n            if (elapsed() > TL) break;\n\n            while (true) {\n                int nxts[4];\n                int cc = list_legal(cur, vis, nxts);\n                if (cc == 0) return out;\n                if (cc >= 2) break;\n\n                int nx = nxts[0];\n                vis[tile[nx]] = 1;\n                out.seq.push_back(nx);\n                out.score += val[nx];\n                cur = nx;\n                if (elapsed() > TL) return out;\n            }\n\n            ReachInfo curInfo = analyze_from_cell(cur, vis, -1, par);\n            if (curInfo.maxTiles <= par.exactLimit && elapsed() < TL - 0.02) {\n                add_decision_pos(out.decisionPos, (int)out.seq.size() - 1);\n                vector<int> suf = exact_finish(cur, vis, par);\n                append_exact_suffix_with_decisions(out, cur, suf);\n                break;\n            }\n\n            int nxts[4];\n            int cc = list_legal(cur, vis, nxts);\n            if (cc == 0) break;\n\n            add_decision_pos(out.decisionPos, (int)out.seq.size() - 1);\n\n            Cand cs[4];\n            for (int i = 0; i < cc; i++) cs[i] = build_macro_candidate(nxts[i], vis, par);\n            if (cc > 1) sort(cs, cs + cc, cand_cmp);\n\n            int pick = 0;\n            if (cc >= 2) {\n                int gap = cs[0].eval - cs[1].eval;\n                double q = par.q;\n                if (gap > 3000) q *= 0.05;\n                else if (gap > 1500) q *= 0.15;\n                else if (gap > 700) q *= 0.35;\n                else if (gap > 300) q *= 0.60;\n                else if (gap > 100) q *= 0.85;\n                else q *= 1.15;\n                if (q > 0.85) q = 0.85;\n\n                while (pick + 1 < cc && rng.next_double() < q) pick++;\n            }\n\n            apply_macro(cs[pick], out);\n            cur = out.seq.back();\n        }\n\n        return out;\n    }\n\n    Solution make_solution(const Built& b) {\n        Solution s;\n        s.seq = b.seq;\n        s.score = b.score;\n        s.decisionPos = b.decisionPos;\n        s.pref.resize(s.seq.size());\n        int sum = 0;\n        for (int i = 0; i < (int)s.seq.size(); i++) {\n            sum += val[s.seq[i]];\n            s.pref[i] = sum;\n        }\n        s.hash = hash_seq(s.seq);\n        return s;\n    }\n\n    void add_solution(const Built& b) {\n        Solution sol = make_solution(b);\n\n        if (bestSol.seq.empty() || sol.score > bestSol.score) {\n            bestSol = sol;\n        }\n\n        for (auto& e : elite) {\n            if (e.hash == sol.hash) {\n                if (sol.score > e.score) e = sol;\n                return;\n            }\n        }\n\n        elite.push_back(sol);\n        sort(elite.begin(), elite.end(), [](const Solution& a, const Solution& b) {\n            return a.score > b.score;\n        });\n        if ((int)elite.size() > ELITE_MAX) elite.resize(ELITE_MAX);\n    }\n\n    const Solution& choose_parent() {\n        if (elite.empty()) return bestSol;\n        double r = rng.next_double();\n        if (elite.size() == 1) return elite[0];\n        if (r < 0.42) return elite[0];\n        if (r < 0.68) return elite[min<int>(1, elite.size() - 1)];\n        if (r < 0.84) return elite[rng.next_int(0, min<int>(2, elite.size() - 1))];\n        return elite[rng.next_int(0, (int)elite.size() - 1)];\n    }\n\n    int choose_cut(const Solution& base) {\n        int L = (int)base.seq.size() - 1;\n        if (L <= 0) return 0;\n        int maxCut = L - 1;\n        if (maxCut <= 0) return 0;\n\n        const vector<int>& dp = base.decisionPos;\n        bool useDecision = !dp.empty() && rng.next_double() < 0.72;\n\n        if (useDecision) {\n            int K = (int)dp.size();\n            int idx = 0;\n            uint32_t mode = rng.next_u32() % 5;\n            if (mode == 0) {\n                idx = 0;\n            } else if (mode == 1) {\n                double u = rng.next_double();\n                idx = (int)((K - 1) * u * u);\n            } else if (mode == 2) {\n                double u = rng.next_double();\n                idx = (int)((K - 1) * u);\n            } else {\n                double u = rng.next_double();\n                idx = (K - 1) - (int)((K - 1) * u * u);\n            }\n            int cut = dp[idx];\n            if (cut < 0) cut = 0;\n            if (cut > maxCut) cut = maxCut;\n            return cut;\n        }\n\n        uint32_t mode = rng.next_u32() % 6;\n        int cut = 0;\n        if (mode == 0) {\n            cut = 0;\n        } else if (mode == 1) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u * u);\n        } else if (mode == 2) {\n            double u = rng.next_double();\n            cut = (int)(maxCut * u);\n        } else if (mode == 3) {\n            double u = rng.next_double();\n            cut = maxCut - (int)(maxCut * u * u);\n        } else {\n            int lo = max(0, maxCut / 3);\n            int hi = maxCut;\n            cut = rng.next_int(lo, hi);\n        }\n        if (cut < 0) cut = 0;\n        if (cut > maxCut) cut = maxCut;\n        return cut;\n    }\n\n    string seq_to_answer(const vector<int>& seq) {\n        string ans;\n        ans.reserve(max(0, (int)seq.size() - 1));\n        for (int i = 1; i < (int)seq.size(); i++) {\n            int a = seq[i - 1], b = seq[i];\n            if (b == a - N) ans.push_back('U');\n            else if (b == a + N) ans.push_back('D');\n            else if (b == a - 1) ans.push_back('L');\n            else ans.push_back('R');\n        }\n        return ans;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        Built init;\n        init.seq = {start};\n        init.score = val[start];\n        init.decisionPos.clear();\n\n        bestSol = make_solution(init);\n        elite.clear();\n        elite.push_back(bestSol);\n\n        for (int rep = 0; rep < 8 && elapsed() < 0.22; rep++) {\n            Params par = sample_params();\n            Built b = grow_from(bestSol, 0, par);\n            add_solution(b);\n        }\n\n        while (elapsed() < TL) {\n            Params par = sample_params();\n\n            bool doRestart = elite.empty() || rng.next_double() < 0.11;\n            if (doRestart) {\n                Built b = grow_from(bestSol, 0, par);\n                add_solution(b);\n                continue;\n            }\n\n            const Solution& base = choose_parent();\n            int cut = choose_cut(base);\n            Built b = grow_from(base, cut, par);\n            add_solution(b);\n        }\n\n        cout << seq_to_answer(bestSol.seq) << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horizontal;\n    int i, j;\n};\n\nstruct Sample {\n    double y = 0.0;\n    double w = 1.0;\n    array<array<unsigned char, 30>, 30> hp{};\n    array<array<unsigned char, 30>, 30> vp{};\n};\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr double PRIOR = 5000.0;\n    static constexpr double INF = 1e100;\n\n    vector<Sample> samples;\n\n    // Avg model\n    double AvgH[N], AvgV[N];\n\n    // Split model\n    int splitH[N], splitV[N];\n    double A[N], B[N];\n    double C[N], Dv[N];\n\n    // Confidence in split model\n    double splitMix = 0.0;\n\n    // Local edge estimates (stored around mixed model)\n    double edgeH[N][N - 1];\n    double edgeV[N - 1][N];\n    int cntH[N][N - 1];\n    int cntV[N - 1][N];\n\n    int curTurn = 0;\n\n    static double clamp_cost(double x) {\n        if (x < 1000.0) return 1000.0;\n        if (x > 9000.0) return 9000.0;\n        return x;\n    }\n\n    static double clamp01(double x) {\n        if (x < 0.0) return 0.0;\n        if (x > 1.0) return 1.0;\n        return x;\n    }\n\n    bool need_rebuild(int turn) const {\n        if (turn == 0) return true;\n        if (turn < 60) return turn % 3 == 0;\n        if (turn < 180) return turn % 6 == 0;\n        return turn % 12 == 0;\n    }\n\n    double local_kappa() const {\n        if (curTurn < 120) return 10.0;\n        if (curTurn < 350) return 8.0;\n        return 6.0;\n    }\n\n    double avg_h(int i, int) const { return AvgH[i]; }\n    double avg_v(int, int j) const { return AvgV[j]; }\n\n    double split_h(int i, int j) const {\n        return (j < splitH[i] ? A[i] : B[i]);\n    }\n    double split_v(int i, int j) const {\n        return (i < splitV[j] ? C[j] : Dv[j]);\n    }\n\n    double mixed_h(int i, int j) const {\n        return clamp_cost((1.0 - splitMix) * AvgH[i] + splitMix * split_h(i, j));\n    }\n    double mixed_v(int i, int j) const {\n        return clamp_cost((1.0 - splitMix) * AvgV[j] + splitMix * split_v(i, j));\n    }\n\n    double route_h_mixed(int i, int j) const {\n        double g = mixed_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return g;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        return clamp_cost(g + alpha * (edgeH[i][j] - g));\n    }\n    double route_v_mixed(int i, int j) const {\n        double g = mixed_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return g;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        return clamp_cost(g + alpha * (edgeV[i][j] - g));\n    }\n\n    // Transfer mixed residuals to avg/split hypotheses\n    double route_h_avg(int i, int j) const {\n        double base = avg_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return base;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        double resid = edgeH[i][j] - mixed_h(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_v_avg(int i, int j) const {\n        double base = avg_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return base;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        double resid = edgeV[i][j] - mixed_v(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_h_split(int i, int j) const {\n        double base = split_h(i, j);\n        int c = cntH[i][j];\n        if (c == 0) return base;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        double resid = edgeH[i][j] - mixed_h(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n    double route_v_split(int i, int j) const {\n        double base = split_v(i, j);\n        int c = cntV[i][j];\n        if (c == 0) return base;\n        double kappa = local_kappa();\n        double alpha = (double)c / (c + kappa);\n        double resid = edgeV[i][j] - mixed_v(i, j);\n        return clamp_cost(base + alpha * resid);\n    }\n\n    double prior_est_h(int i, int j) const {\n        if (cntH[i][j] == 0) return mixed_h(i, j);\n        return route_h_mixed(i, j);\n    }\n    double prior_est_v(int i, int j) const {\n        if (cntV[i][j] == 0) return mixed_v(i, j);\n        return route_v_mixed(i, j);\n    }\n\n    void fit_avg_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                AvgH[i] = PRIOR;\n                AvgV[i] = PRIOR;\n            }\n            return;\n        }\n\n        vector<double> pred(m, 0.0);\n        auto rebuild_pred = [&]() {\n            fill(pred.begin(), pred.end(), 0.0);\n            for (int n = 0; n < m; n++) {\n                double s = 0.0;\n                for (int i = 0; i < N; i++) s += (int)samples[n].hp[i][29] * AvgH[i];\n                for (int j = 0; j < N; j++) s += (int)samples[n].vp[j][29] * AvgV[j];\n                pred[n] = s;\n            }\n        };\n        rebuild_pred();\n\n        double lambda = 35.0 / sqrt((double)m + 1.0) + 1.5;\n\n        for (int it = 0; it < 8; it++) {\n            for (int i = 0; i < N; i++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].hp[i][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + AvgH[i] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - AvgH[i];\n                if (fabs(delta) > 1e-12) {\n                    AvgH[i] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].hp[i][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                double num = 0.0, den = 0.0;\n                for (int n = 0; n < m; n++) {\n                    double f = (int)samples[n].vp[j][29];\n                    if (f == 0.0) continue;\n                    double w = samples[n].w;\n                    num += w * f * (samples[n].y - pred[n] + AvgV[j] * f);\n                    den += w * f * f;\n                }\n                double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n                double delta = nv - AvgV[j];\n                if (fabs(delta) > 1e-12) {\n                    AvgV[j] = nv;\n                    for (int n = 0; n < m; n++) {\n                        double f = (int)samples[n].vp[j][29];\n                        if (f) pred[n] += delta * f;\n                    }\n                }\n            }\n        }\n    }\n\n    void compute_pred_split(vector<double>& pred) const {\n        int m = (int)samples.size();\n        pred.assign(m, 0.0);\n        for (int n = 0; n < m; n++) {\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)samples[n].hp[i][splitH[i]];\n                int t = (int)samples[n].hp[i][29];\n                s += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)samples[n].vp[j][splitV[j]];\n                int t = (int)samples[n].vp[j][29];\n                s += u * C[j] + (t - u) * Dv[j];\n            }\n            pred[n] = s;\n        }\n    }\n\n    void cd_update_param(double& param, vector<double>& pred, double lambda,\n                         const function<int(const Sample&)>& feat) {\n        int m = (int)samples.size();\n        double num = 0.0, den = 0.0;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f == 0.0) continue;\n            double w = samples[n].w;\n            num += w * f * (samples[n].y - pred[n] + param * f);\n            den += w * f * f;\n        }\n        double nv = clamp_cost((num + lambda * PRIOR) / (den + lambda));\n        double delta = nv - param;\n        if (fabs(delta) <= 1e-12) return;\n        param = nv;\n        for (int n = 0; n < m; n++) {\n            double f = feat(samples[n]);\n            if (f) pred[n] += delta * f;\n        }\n    }\n\n    void fit_fixed_splits(vector<double>& pred, double lambda, int iters) {\n        int m = (int)samples.size();\n        if (m == 0) return;\n        compute_pred_split(pred);\n\n        for (int it = 0; it < iters; it++) {\n            for (int i = 0; i < N; i++) {\n                int sp = splitH[i];\n                cd_update_param(A[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    return (int)s.hp[i][sp];\n                });\n                cd_update_param(B[i], pred, lambda, [i, sp](const Sample& s) -> int {\n                    int l = (int)s.hp[i][sp];\n                    int t = (int)s.hp[i][29];\n                    return t - l;\n                });\n            }\n            for (int j = 0; j < N; j++) {\n                int sp = splitV[j];\n                cd_update_param(C[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    return (int)s.vp[j][sp];\n                });\n                cd_update_param(Dv[j], pred, lambda, [j, sp](const Sample& s) -> int {\n                    int u = (int)s.vp[j][sp];\n                    int t = (int)s.vp[j][29];\n                    return t - u;\n                });\n            }\n        }\n    }\n\n    void optimize_row_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int i = 0; i < N; i++) {\n            int oldsp = splitH[i];\n            double oldA = A[i], oldB = B[i];\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int tot = (int)samples[n].hp[i][29];\n                int oldr = tot - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double tt = 0.0, tr = 0.0, rr1 = 0.0;\n            for (int n = 0; n < m; n++) {\n                double w = samples[n].w;\n                int t = (int)samples[n].hp[i][29];\n                double r = base[n];\n                tt += w * t * t;\n                tr += w * t * r;\n                rr1 += w * r * r;\n            }\n            double one = clamp_cost((tr + lambda * PRIOR) / (tt + lambda));\n            double loss1 = rr1 - 2.0 * one * tr + one * one * tt + lambda * (one - PRIOR) * (one - PRIOR);\n\n            double bestLoss = 1e300;\n            int bestSp = 15;\n            double bestA = one, bestB = one;\n            double bestLeftSup = 0.0, bestRightSup = 0.0;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n                double leftSup = 0.0, rightSup = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].hp[i][sp];\n                    int t = (int)samples[n].hp[i][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                    leftSup += w * a;\n                    rightSup += w * b;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double na = PRIOR, nb = PRIOR;\n                if (det > 1e-9) {\n                    na = (R0 * M11 - R1 * M01) / det;\n                    nb = (R1 * M00 - R0 * M01) / det;\n                }\n                na = clamp_cost(na);\n                nb = clamp_cost(nb);\n\n                double loss =\n                    rr\n                    - 2.0 * na * ar - 2.0 * nb * br\n                    + na * na * aa + 2.0 * na * nb * ab + nb * nb * bb\n                    + lambda * ((na - PRIOR) * (na - PRIOR) + (nb - PRIOR) * (nb - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestA = na;\n                    bestB = nb;\n                    bestLeftSup = leftSup;\n                    bestRightSup = rightSup;\n                }\n            }\n\n            bool useSplit = false;\n            double improve = loss1 - bestLoss;\n            if (min(bestLeftSup, bestRightSup) >= 18.0 &&\n                fabs(bestA - bestB) >= 180.0 &&\n                improve >= max(3e5, 0.0025 * loss1)) {\n                useSplit = true;\n            }\n\n            int newSp = useSplit ? bestSp : 15;\n            double newA = useSplit ? bestA : one;\n            double newB = useSplit ? bestB : one;\n\n            splitH[i] = newSp;\n            A[i] = newA;\n            B[i] = newB;\n\n            for (int n = 0; n < m; n++) {\n                int oldl = (int)samples[n].hp[i][oldsp];\n                int oldt = (int)samples[n].hp[i][29];\n                int oldr = oldt - oldl;\n                double oldc = oldl * oldA + oldr * oldB;\n\n                int newl = (int)samples[n].hp[i][newSp];\n                int newr = oldt - newl;\n                double newc = newl * newA + newr * newB;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void optimize_col_splits(vector<double>& pred, double lambda) {\n        int m = (int)samples.size();\n        vector<double> base(m);\n\n        for (int j = 0; j < N; j++) {\n            int oldsp = splitV[j];\n            double oldC = C[j], oldD = Dv[j];\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int tot = (int)samples[n].vp[j][29];\n                int oldd = tot - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n                base[n] = samples[n].y - (pred[n] - oldc);\n            }\n\n            double tt = 0.0, tr = 0.0, rr1 = 0.0;\n            for (int n = 0; n < m; n++) {\n                double w = samples[n].w;\n                int t = (int)samples[n].vp[j][29];\n                double r = base[n];\n                tt += w * t * t;\n                tr += w * t * r;\n                rr1 += w * r * r;\n            }\n            double one = clamp_cost((tr + lambda * PRIOR) / (tt + lambda));\n            double loss1 = rr1 - 2.0 * one * tr + one * one * tt + lambda * (one - PRIOR) * (one - PRIOR);\n\n            double bestLoss = 1e300;\n            int bestSp = 15;\n            double bestC = one, bestD = one;\n            double bestUpSup = 0.0, bestDownSup = 0.0;\n\n            for (int sp = 1; sp <= 28; sp++) {\n                double aa = 0.0, ab = 0.0, bb = 0.0;\n                double ar = 0.0, br = 0.0, rr = 0.0;\n                double upSup = 0.0, downSup = 0.0;\n\n                for (int n = 0; n < m; n++) {\n                    double w = samples[n].w;\n                    double r = base[n];\n                    int a = (int)samples[n].vp[j][sp];\n                    int t = (int)samples[n].vp[j][29];\n                    int b = t - a;\n                    aa += w * a * a;\n                    ab += w * a * b;\n                    bb += w * b * b;\n                    ar += w * a * r;\n                    br += w * b * r;\n                    rr += w * r * r;\n                    upSup += w * a;\n                    downSup += w * b;\n                }\n\n                double M00 = aa + lambda;\n                double M11 = bb + lambda;\n                double M01 = ab;\n                double R0 = ar + lambda * PRIOR;\n                double R1 = br + lambda * PRIOR;\n\n                double det = M00 * M11 - M01 * M01;\n                double nc = PRIOR, nd = PRIOR;\n                if (det > 1e-9) {\n                    nc = (R0 * M11 - R1 * M01) / det;\n                    nd = (R1 * M00 - R0 * M01) / det;\n                }\n                nc = clamp_cost(nc);\n                nd = clamp_cost(nd);\n\n                double loss =\n                    rr\n                    - 2.0 * nc * ar - 2.0 * nd * br\n                    + nc * nc * aa + 2.0 * nc * nd * ab + nd * nd * bb\n                    + lambda * ((nc - PRIOR) * (nc - PRIOR) + (nd - PRIOR) * (nd - PRIOR));\n\n                if (loss < bestLoss) {\n                    bestLoss = loss;\n                    bestSp = sp;\n                    bestC = nc;\n                    bestD = nd;\n                    bestUpSup = upSup;\n                    bestDownSup = downSup;\n                }\n            }\n\n            bool useSplit = false;\n            double improve = loss1 - bestLoss;\n            if (min(bestUpSup, bestDownSup) >= 18.0 &&\n                fabs(bestC - bestD) >= 180.0 &&\n                improve >= max(3e5, 0.0025 * loss1)) {\n                useSplit = true;\n            }\n\n            int newSp = useSplit ? bestSp : 15;\n            double newC = useSplit ? bestC : one;\n            double newD = useSplit ? bestD : one;\n\n            splitV[j] = newSp;\n            C[j] = newC;\n            Dv[j] = newD;\n\n            for (int n = 0; n < m; n++) {\n                int oldu = (int)samples[n].vp[j][oldsp];\n                int oldt = (int)samples[n].vp[j][29];\n                int oldd = oldt - oldu;\n                double oldc = oldu * oldC + oldd * oldD;\n\n                int newu = (int)samples[n].vp[j][newSp];\n                int newd = oldt - newu;\n                double newc = newu * newC + newd * newD;\n\n                pred[n] += newc - oldc;\n            }\n        }\n    }\n\n    void fit_split_model() {\n        int m = (int)samples.size();\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = AvgH[i];\n                C[i] = Dv[i] = AvgV[i];\n            }\n            return;\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!(1000.0 <= A[i] && A[i] <= 9000.0)) A[i] = AvgH[i];\n            if (!(1000.0 <= B[i] && B[i] <= 9000.0)) B[i] = AvgH[i];\n            if (!(1000.0 <= C[i] && C[i] <= 9000.0)) C[i] = AvgV[i];\n            if (!(1000.0 <= Dv[i] && Dv[i] <= 9000.0)) Dv[i] = AvgV[i];\n            if (splitH[i] < 1 || splitH[i] > 28) splitH[i] = 15;\n            if (splitV[i] < 1 || splitV[i] > 28) splitV[i] = 15;\n        }\n\n        double lambda = 14.0 / sqrt((double)m + 1.0) + 0.9;\n        vector<double> pred;\n\n        fit_fixed_splits(pred, lambda, 4);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n        fit_fixed_splits(pred, lambda, 2);\n        optimize_row_splits(pred, lambda);\n        optimize_col_splits(pred, lambda);\n    }\n\n    double loss_avg_model() const {\n        double loss = 0.0;\n        for (const auto& s : samples) {\n            double pred = 0.0;\n            for (int i = 0; i < N; i++) pred += (int)s.hp[i][29] * AvgH[i];\n            for (int j = 0; j < N; j++) pred += (int)s.vp[j][29] * AvgV[j];\n            double d = pred - s.y;\n            loss += s.w * d * d;\n        }\n        return loss;\n    }\n\n    double loss_split_model() const {\n        double loss = 0.0;\n        for (const auto& s : samples) {\n            double pred = 0.0;\n            for (int i = 0; i < N; i++) {\n                int l = (int)s.hp[i][splitH[i]];\n                int t = (int)s.hp[i][29];\n                pred += l * A[i] + (t - l) * B[i];\n            }\n            for (int j = 0; j < N; j++) {\n                int u = (int)s.vp[j][splitV[j]];\n                int t = (int)s.vp[j][29];\n                pred += u * C[j] + (t - u) * Dv[j];\n            }\n            double d = pred - s.y;\n            loss += s.w * d * d;\n        }\n        return loss;\n    }\n\n    void recenter_local_edges() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) continue;\n                double g = mixed_h(i, j);\n                double keep = (double)cntH[i][j] / (cntH[i][j] + 4.0);\n                edgeH[i][j] = clamp_cost(g + keep * (edgeH[i][j] - g));\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) continue;\n                double g = mixed_v(i, j);\n                double keep = (double)cntV[i][j] / (cntV[i][j] + 4.0);\n                edgeV[i][j] = clamp_cost(g + keep * (edgeV[i][j] - g));\n            }\n        }\n    }\n\n    void rebuild_model() {\n        int m = (int)samples.size();\n\n        if (m == 0) {\n            for (int i = 0; i < N; i++) {\n                AvgH[i] = AvgV[i] = PRIOR;\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n            }\n            splitMix = 0.0;\n            return;\n        }\n\n        double oldMix = splitMix;\n\n        fit_avg_model();\n\n        if (m < 70) {\n            for (int i = 0; i < N; i++) {\n                splitH[i] = splitV[i] = 15;\n                A[i] = B[i] = AvgH[i];\n                C[i] = Dv[i] = AvgV[i];\n            }\n            splitMix = 0.0;\n            recenter_local_edges();\n            return;\n        }\n\n        fit_split_model();\n\n        double lossAvg = loss_avg_model();\n        double lossSplit = loss_split_model();\n        double relImprove = max(0.0, lossAvg - lossSplit) / max(1.0, lossAvg);\n\n        int splitCount = 0;\n        for (int i = 0; i < N; i++) {\n            if (fabs(A[i] - B[i]) >= 1e-9) splitCount++;\n            if (fabs(C[i] - Dv[i]) >= 1e-9) splitCount++;\n        }\n        double countFactor = min(1.0, splitCount / 20.0);\n\n        double rawMix = (relImprove - 0.0015) / 0.0055;\n        rawMix = clamp01(rawMix);\n        rawMix *= (0.75 + 0.25 * countFactor);\n\n        double sampleFactor = clamp01((m - 60.0) / 160.0);\n        rawMix *= (0.7 + 0.3 * sampleFactor);\n\n        double keepOld = (m < 160 ? 0.35 : 0.20);\n        splitMix = clamp01(keepOld * oldMix + (1.0 - keepOld) * rawMix);\n\n        recenter_local_edges();\n    }\n\n    enum Mode {\n        ROUTE_AVG = 0,\n        ROUTE_MIXED = 1,\n        ROUTE_SPLIT = 2,\n        GLOBAL_AVG = 3,\n        GLOBAL_MIXED = 4,\n        GLOBAL_SPLIT = 5\n    };\n\n    double weight_h(Mode mode, int i, int j) const {\n        switch (mode) {\n            case ROUTE_AVG:    return route_h_avg(i, j);\n            case ROUTE_MIXED:  return route_h_mixed(i, j);\n            case ROUTE_SPLIT:  return route_h_split(i, j);\n            case GLOBAL_AVG:   return avg_h(i, j);\n            case GLOBAL_MIXED: return mixed_h(i, j);\n            case GLOBAL_SPLIT: return split_h(i, j);\n        }\n        return PRIOR;\n    }\n\n    double weight_v(Mode mode, int i, int j) const {\n        switch (mode) {\n            case ROUTE_AVG:    return route_v_avg(i, j);\n            case ROUTE_MIXED:  return route_v_mixed(i, j);\n            case ROUTE_SPLIT:  return route_v_split(i, j);\n            case GLOBAL_AVG:   return avg_v(i, j);\n            case GLOBAL_MIXED: return mixed_v(i, j);\n            case GLOBAL_SPLIT: return split_v(i, j);\n        }\n        return PRIOR;\n    }\n\n    string shortest_path_mode(int si, int sj, int ti, int tj, Mode mode) const {\n        const int V = N * N;\n        auto id = [&](int x, int y) { return x * N + y; };\n\n        vector<double> dist(V, INF);\n        vector<int> par(V, -1);\n        vector<char> mv(V, 0);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        int s = id(si, sj), t = id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == t) break;\n\n            int x = u / N;\n            int y = u % N;\n\n            auto relax = [&](int nx, int ny, double w, char c) {\n                int v = id(nx, ny);\n                double nd = d + w;\n                if (nd + 1e-12 < dist[v]) {\n                    dist[v] = nd;\n                    par[v] = u;\n                    mv[v] = c;\n                    pq.push({nd, v});\n                }\n            };\n\n            if (x > 0) relax(x - 1, y, weight_v(mode, x - 1, y), 'U');\n            if (x + 1 < N) relax(x + 1, y, weight_v(mode, x, y), 'D');\n            if (y > 0) relax(x, y - 1, weight_h(mode, x, y - 1), 'L');\n            if (y + 1 < N) relax(x, y + 1, weight_h(mode, x, y), 'R');\n        }\n\n        string path;\n        for (int cur = t; cur != s; cur = par[cur]) path.push_back(mv[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    struct PathEval {\n        double routeAvg = 0.0;\n        double routeMixed = 0.0;\n        double routeSplit = 0.0;\n        double globalAvg = 0.0;\n        double globalMixed = 0.0;\n        double globalSplit = 0.0;\n    };\n\n    PathEval eval_path(int si, int sj, const string& path) const {\n        PathEval pe;\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                pe.routeAvg += route_v_avg(x - 1, y);\n                pe.routeMixed += route_v_mixed(x - 1, y);\n                pe.routeSplit += route_v_split(x - 1, y);\n                pe.globalAvg += avg_v(x - 1, y);\n                pe.globalMixed += mixed_v(x - 1, y);\n                pe.globalSplit += split_v(x - 1, y);\n                --x;\n            } else if (c == 'D') {\n                pe.routeAvg += route_v_avg(x, y);\n                pe.routeMixed += route_v_mixed(x, y);\n                pe.routeSplit += route_v_split(x, y);\n                pe.globalAvg += avg_v(x, y);\n                pe.globalMixed += mixed_v(x, y);\n                pe.globalSplit += split_v(x, y);\n                ++x;\n            } else if (c == 'L') {\n                pe.routeAvg += route_h_avg(x, y - 1);\n                pe.routeMixed += route_h_mixed(x, y - 1);\n                pe.routeSplit += route_h_split(x, y - 1);\n                pe.globalAvg += avg_h(x, y - 1);\n                pe.globalMixed += mixed_h(x, y - 1);\n                pe.globalSplit += split_h(x, y - 1);\n                --y;\n            } else if (c == 'R') {\n                pe.routeAvg += route_h_avg(x, y);\n                pe.routeMixed += route_h_mixed(x, y);\n                pe.routeSplit += route_h_split(x, y);\n                pe.globalAvg += avg_h(x, y);\n                pe.globalMixed += mixed_h(x, y);\n                pe.globalSplit += split_h(x, y);\n                ++y;\n            }\n        }\n        return pe;\n    }\n\n    string choose_path(int si, int sj, int ti, int tj, int turn) const {\n        vector<string> cands;\n        cands.reserve(6);\n\n        auto add_cand = [&](const string& s) {\n            for (const string& t : cands) {\n                if (t == s) return;\n            }\n            cands.push_back(s);\n        };\n\n        add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_MIXED));\n        add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_MIXED));\n        add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_AVG));\n\n        if (splitMix <= 0.40 && turn >= 50) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_AVG));\n        }\n        if (splitMix >= 0.18) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, GLOBAL_SPLIT));\n        }\n        if (splitMix >= 0.65 && turn >= 80) {\n            add_cand(shortest_path_mode(si, sj, ti, tj, ROUTE_SPLIT));\n        }\n\n        vector<PathEval> ev(cands.size());\n        vector<double> routeScore(cands.size()), globalScore(cands.size());\n        double bestRouteMixed = INF, bestGlobalScore = INF;\n\n        double p = splitMix;\n        double stabilizer = 0.18 * (1.0 - fabs(2.0 * p - 1.0));\n        double trustLocal = 0.16 + 0.72 * min(1.0, turn / 280.0);\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            ev[i] = eval_path(si, sj, cands[i]);\n\n            double routeHyp = (1.0 - p) * ev[i].routeAvg + p * ev[i].routeSplit;\n            double globalHyp = (1.0 - p) * ev[i].globalAvg + p * ev[i].globalSplit;\n\n            routeScore[i] = (1.0 - stabilizer) * routeHyp + stabilizer * ev[i].routeMixed;\n            globalScore[i] = (1.0 - stabilizer) * globalHyp + stabilizer * ev[i].globalMixed;\n\n            bestRouteMixed = min(bestRouteMixed, ev[i].routeMixed);\n            bestGlobalScore = min(bestGlobalScore, globalScore[i]);\n        }\n\n        int bestIdx = 0;\n        double bestScore = INF;\n        for (int i = 0; i < (int)cands.size(); i++) {\n            double score = trustLocal * routeScore[i] + (1.0 - trustLocal) * globalScore[i];\n\n            if (ev[i].routeMixed > bestRouteMixed * 1.022 + 3200.0) {\n                score += 1e12;\n            }\n            if (globalScore[i] > bestGlobalScore * 1.016 + 2200.0) {\n                score += 5e11;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestIdx = i;\n            }\n        }\n\n        return cands[bestIdx];\n    }\n\n    void build_sample_and_edges(int si, int sj, const string& path, Sample& smp,\n                                vector<EdgeRef>& edges) const {\n        bool hused[N][N - 1] = {};\n        bool vused[N - 1][N] = {};\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int x = si, y = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                vused[x - 1][y] = true;\n                edges.push_back({false, x - 1, y});\n                --x;\n            } else if (c == 'D') {\n                vused[x][y] = true;\n                edges.push_back({false, x, y});\n                ++x;\n            } else if (c == 'L') {\n                hused[x][y - 1] = true;\n                edges.push_back({true, x, y - 1});\n                --y;\n            } else if (c == 'R') {\n                hused[x][y] = true;\n                edges.push_back({true, x, y});\n                ++y;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            smp.hp[i][0] = 0;\n            for (int j = 0; j < N - 1; j++) {\n                smp.hp[i][j + 1] = smp.hp[i][j] + (hused[i][j] ? 1 : 0);\n            }\n        }\n        for (int j = 0; j < N; j++) {\n            smp.vp[j][0] = 0;\n            for (int i = 0; i < N - 1; i++) {\n                smp.vp[j][i + 1] = smp.vp[j][i] + (vused[i][j] ? 1 : 0);\n            }\n        }\n    }\n\n    void update_local_edges(const vector<EdgeRef>& edges, double observed, int turn, double sampleWeight) {\n        if (edges.empty()) return;\n\n        vector<double> gains(edges.size());\n        double pred = 0.0, gsum = 0.0;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            if (e.horizontal) {\n                pred += prior_est_h(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntH[e.i][e.j] + 1.0);\n            } else {\n                pred += prior_est_v(e.i, e.j);\n                gains[k] = 1.0 / sqrt(cntV[e.i][e.j] + 1.0);\n            }\n            gsum += gains[k];\n        }\n\n        double residual = observed - pred;\n\n        double eta;\n        if (turn < 80) eta = 0.33;\n        else if (turn < 250) eta = 0.25;\n        else eta = 0.18;\n\n        double scale = sqrt(sampleWeight);\n        scale = max(0.75, min(1.12, scale));\n        eta *= scale;\n\n        for (size_t k = 0; k < edges.size(); k++) {\n            const auto& e = edges[k];\n            double delta = eta * residual * gains[k] / gsum;\n            delta = max(-800.0, min(800.0, delta));\n\n            if (e.horizontal) {\n                if (cntH[e.i][e.j] == 0) edgeH[e.i][e.j] = mixed_h(e.i, e.j);\n                edgeH[e.i][e.j] = clamp_cost(edgeH[e.i][e.j] + delta);\n\n                double g = mixed_h(e.i, e.j);\n                double cap = 2400.0;\n                edgeH[e.i][e.j] = min(edgeH[e.i][e.j], g + cap);\n                edgeH[e.i][e.j] = max(edgeH[e.i][e.j], g - cap);\n                cntH[e.i][e.j]++;\n            } else {\n                if (cntV[e.i][e.j] == 0) edgeV[e.i][e.j] = mixed_v(e.i, e.j);\n                edgeV[e.i][e.j] = clamp_cost(edgeV[e.i][e.j] + delta);\n\n                double g = mixed_v(e.i, e.j);\n                double cap = 2400.0;\n                edgeV[e.i][e.j] = min(edgeV[e.i][e.j], g + cap);\n                edgeV[e.i][e.j] = max(edgeV[e.i][e.j], g - cap);\n                cntV[e.i][e.j]++;\n            }\n        }\n    }\n\npublic:\n    Solver() {\n        for (int i = 0; i < N; i++) {\n            AvgH[i] = AvgV[i] = PRIOR;\n            splitH[i] = splitV[i] = 15;\n            A[i] = B[i] = C[i] = Dv[i] = PRIOR;\n        }\n        splitMix = 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                edgeH[i][j] = PRIOR;\n                cntH[i][j] = 0;\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                edgeV[i][j] = PRIOR;\n                cntV[i][j] = 0;\n            }\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int turn = 0; turn < 1000; turn++) {\n            curTurn = turn;\n            if (need_rebuild(turn)) rebuild_model();\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            string path = choose_path(si, sj, ti, tj, turn);\n\n            cout << path << '\\n';\n            cout.flush();\n\n            long long feedback;\n            cin >> feedback;\n\n            Sample smp;\n            smp.y = (double)feedback;\n\n            double base = max(50000.0, smp.y);\n            double scale = 200000.0 / base;\n            smp.w = scale * scale;\n            smp.w = max(0.35, min(3.0, smp.w));\n\n            vector<EdgeRef> edges;\n            build_sample_and_edges(si, sj, path, smp, edges);\n\n            samples.push_back(smp);\n            update_local_edges(edges, smp.y, turn, smp.w);\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAXL = 12;\nstatic constexpr int MINL = 2;\nstatic constexpr int WORDS = 13; // ceil(800/64)\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\nstatic inline int ch2v(char c) { return c - 'A'; }\nstatic inline char v2ch(int v) { return char('A' + v); }\n\nusing Bits = array<uint64_t, WORDS>;\n\ntemplate<class B>\nstatic inline bool getbit(const B& b, int i) {\n    return (b[i >> 6] >> (i & 63)) & 1ULL;\n}\ntemplate<class B>\nstatic inline void setbit(B& b, int i) {\n    b[i >> 6] |= 1ULL << (i & 63);\n}\n\nstruct Pattern {\n    int len;\n    uint64_t code;\n    int weight;\n    string s;\n};\n\nstruct ACNode {\n    array<int, 8> next{};\n    int link = 0;\n    vector<int> out;\n    ACNode() { next.fill(-1); }\n};\n\nstruct BeamState {\n    int node = 0;\n    int score = 0;\n    Bits seen{};\n    array<uint8_t, N> s{};\n};\n\nstruct Candidate {\n    array<uint8_t, N> row{};\n    Bits bits{};\n    string canon;\n};\n\nstruct MatrixState {\n    array<array<uint8_t, N>, N> a{};\n    array<Bits, N> row_bits{};\n    array<Bits, N> col_bits{};\n    vector<int> cnt;\n    int score = 0;\n};\n\nstruct Solver {\n    int M, K;\n    vector<Pattern> pats;\n    vector<int> orig_weight;\n    array<unordered_map<uint64_t, int>, MAXL + 1> id_of;\n    vector<ACNode> ac;\n\n    array<unordered_map<uint64_t, array<int, 8>>, MAXL> next_cnt;\n    array<unordered_map<uint64_t, array<int, 8>>, MAXL> prev_cnt;\n    array<int, 8> char_freq{};\n\n    mt19937_64 rng;\n    Timer timer;\n\n    Solver() : rng(chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    uint64_t encode_string(const string& s) {\n        uint64_t code = 0;\n        for (char c : s) code = (code << 3) | (uint64_t)ch2v(c);\n        return code;\n    }\n\n    string decode_string(uint64_t code, int len) {\n        string s(len, 'A');\n        for (int i = len - 1; i >= 0; --i) {\n            s[i] = v2ch((int)(code & 7ULL));\n            code >>= 3;\n        }\n        return s;\n    }\n\n    void add_pattern_to_ac(const string& s, int id) {\n        int v = 0;\n        for (char c : s) {\n            int x = ch2v(c);\n            if (ac[v].next[x] == -1) {\n                ac[v].next[x] = (int)ac.size();\n                ac.emplace_back();\n            }\n            v = ac[v].next[x];\n        }\n        ac[v].out.push_back(id);\n    }\n\n    void build_ac() {\n        ac.clear();\n        ac.emplace_back();\n        for (int id = 0; id < K; ++id) add_pattern_to_ac(pats[id].s, id);\n\n        queue<int> q;\n        for (int c = 0; c < 8; ++c) {\n            int u = ac[0].next[c];\n            if (u == -1) ac[0].next[c] = 0;\n            else {\n                ac[u].link = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            int lk = ac[v].link;\n            if (!ac[lk].out.empty()) {\n                auto& dst = ac[v].out;\n                auto& src = ac[lk].out;\n                dst.insert(dst.end(), src.begin(), src.end());\n            }\n            for (int c = 0; c < 8; ++c) {\n                int u = ac[v].next[c];\n                if (u == -1) ac[v].next[c] = ac[lk].next[c];\n                else {\n                    ac[u].link = ac[lk].next[c];\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    void build_transition_stats() {\n        for (int t = 0; t < MAXL; ++t) {\n            next_cnt[t].clear();\n            prev_cnt[t].clear();\n        }\n        char_freq.fill(0);\n\n        for (const auto& p : pats) {\n            const string& s = p.s;\n            int L = p.len;\n            int w = p.weight;\n\n            for (char c : s) char_freq[ch2v(c)] += w;\n\n            for (int i = 0; i < L; ++i) {\n                uint64_t code = 0;\n                for (int t = 1; t <= 11 && i + t <= L; ++t) {\n                    code = (code << 3) | (uint64_t)ch2v(s[i + t - 1]);\n                    if (i + t < L) {\n                        auto& arr = next_cnt[t][code];\n                        arr[ch2v(s[i + t])] += w;\n                    }\n                    if (i > 0) {\n                        auto& arr = prev_cnt[t][code];\n                        arr[ch2v(s[i - 1])] += w;\n                    }\n                }\n            }\n        }\n    }\n\n    Bits compute_bits_seq(const uint8_t seq[N]) const {\n        Bits bits{};\n        bits.fill(0);\n        for (int st = 0; st < N; ++st) {\n            uint64_t code = 0;\n            for (int len = 1; len <= MAXL; ++len) {\n                code = (code << 3) | (uint64_t)seq[(st + len - 1) % N];\n                if (len >= MINL) {\n                    auto it = id_of[len].find(code);\n                    if (it != id_of[len].end()) setbit(bits, it->second);\n                }\n            }\n        }\n        return bits;\n    }\n\n    Bits compute_row_bits(const MatrixState& ms, int r) const {\n        uint8_t seq[N];\n        for (int c = 0; c < N; ++c) seq[c] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    Bits compute_col_bits(const MatrixState& ms, int c) const {\n        uint8_t seq[N];\n        for (int r = 0; r < N; ++r) seq[r] = ms.a[r][c];\n        return compute_bits_seq(seq);\n    }\n\n    int gain_by_bits(const Bits& bits, const vector<int>& weight) const {\n        int g = 0;\n        for (int id = 0; id < K; ++id) if (getbit(bits, id)) g += weight[id];\n        return g;\n    }\n\n    int row_gain_and_bits(const array<uint8_t, N>& row, const vector<int>& weight, Bits& bits) const {\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        bits = compute_bits_seq(seq);\n        return gain_by_bits(bits, weight);\n    }\n\n    string canonical_row(const array<uint8_t, N>& row) const {\n        string best(N, 'Z');\n        for (int sh = 0; sh < N; ++sh) {\n            string cur(N, 'A');\n            for (int i = 0; i < N; ++i) cur[i] = v2ch(row[(i + sh) % N]);\n            if (cur < best) best = cur;\n        }\n        return best;\n    }\n\n    array<uint8_t, N> fallback_row(const vector<int>& weight) {\n        int best_id = -1, best_key = -1;\n        for (int i = 0; i < K; ++i) {\n            int key = weight[i] * pats[i].len;\n            if (key > best_key) best_key = key, best_id = i;\n        }\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = rng() % 8;\n        if (best_id != -1) {\n            const string& s = pats[best_id].s;\n            for (int i = 0; i < (int)s.size() && i < N; ++i) row[i] = ch2v(s[i]);\n        }\n        return row;\n    }\n\n    vector<int> pick_seed_patterns(const vector<int>& weight, int topk, int randk) {\n        vector<pair<int,int>> v;\n        v.reserve(K);\n        for (int i = 0; i < K; ++i) {\n            if (weight[i] <= 0) continue;\n            int key = weight[i] * pats[i].len;\n            v.push_back({key, i});\n        }\n        sort(v.begin(), v.end(), greater<pair<int,int>>());\n\n        vector<int> res;\n        for (int i = 0; i < (int)v.size() && i < topk; ++i) res.push_back(v[i].second);\n\n        vector<int> rest;\n        for (int i = topk; i < (int)v.size(); ++i) rest.push_back(v[i].second);\n        shuffle(rest.begin(), rest.end(), rng);\n        for (int i = 0; i < (int)rest.size() && i < randk; ++i) res.push_back(rest[i]);\n        return res;\n    }\n\n    array<uint8_t, N> beam_search_row(const vector<int>& weight, const vector<uint8_t>& prefix, int BEAM = 120) {\n        if ((int)prefix.size() > N) return fallback_row(weight);\n\n        vector<BeamState> beam(1);\n        beam[0].node = 0;\n        beam[0].score = 0;\n        beam[0].seen.fill(0);\n\n        int pos = 0;\n        for (uint8_t c : prefix) {\n            beam[0].s[pos++] = c;\n            beam[0].node = ac[beam[0].node].next[c];\n            for (int id : ac[beam[0].node].out) {\n                if (weight[id] > 0 && !getbit(beam[0].seen, id)) {\n                    setbit(beam[0].seen, id);\n                    beam[0].score += weight[id];\n                }\n            }\n        }\n\n        for (int d = pos; d < N; ++d) {\n            vector<BeamState> cand;\n            cand.reserve(beam.size() * 8);\n            for (const auto& st : beam) {\n                for (int c = 0; c < 8; ++c) {\n                    BeamState ns = st;\n                    ns.s[d] = (uint8_t)c;\n                    ns.node = ac[st.node].next[c];\n                    for (int id : ac[ns.node].out) {\n                        if (weight[id] > 0 && !getbit(ns.seen, id)) {\n                            setbit(ns.seen, id);\n                            ns.score += weight[id];\n                        }\n                    }\n                    cand.push_back(std::move(ns));\n                }\n            }\n\n            auto cmp = [](const BeamState& a, const BeamState& b) {\n                return a.score > b.score;\n            };\n            if ((int)cand.size() > BEAM) {\n                nth_element(cand.begin(), cand.begin() + BEAM, cand.end(), cmp);\n                cand.resize(BEAM);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n            beam.swap(cand);\n        }\n\n        int best_gain = -1;\n        array<uint8_t, N> best_row{};\n        int take = min<int>(24, beam.size());\n        for (int i = 0; i < take; ++i) {\n            Bits bits{};\n            int g = row_gain_and_bits(beam[i].s, weight, bits);\n            if (g > best_gain) {\n                best_gain = g;\n                best_row = beam[i].s;\n            }\n        }\n        if (best_gain <= 0) return fallback_row(weight);\n        return best_row;\n    }\n\n    pair<int, uint8_t> best_extend_char(const deque<uint8_t>& dq, bool to_left) {\n        array<int, 8> score{};\n        for (int c = 0; c < 8; ++c) score[c] = char_freq[c] / 32;\n\n        int lim = min<int>(11, dq.size());\n        for (int t = 1; t <= lim; ++t) {\n            uint64_t code = 0;\n            if (!to_left) {\n                for (int i = (int)dq.size() - t; i < (int)dq.size(); ++i) code = (code << 3) | dq[i];\n                auto it = next_cnt[t].find(code);\n                if (it != next_cnt[t].end()) {\n                    for (int c = 0; c < 8; ++c) score[c] += it->second[c] * t * t;\n                }\n            } else {\n                for (int i = 0; i < t; ++i) code = (code << 3) | dq[i];\n                auto it = prev_cnt[t].find(code);\n                if (it != prev_cnt[t].end()) {\n                    for (int c = 0; c < 8; ++c) score[c] += it->second[c] * t * t;\n                }\n            }\n        }\n\n        int best_score = -1, best_c = 0;\n        for (int c = 0; c < 8; ++c) if (score[c] > best_score) best_score = score[c], best_c = c;\n        return {best_score, (uint8_t)best_c};\n    }\n\n    array<uint8_t, N> transition_extend_from_seed(const string& seed, int mode) {\n        deque<uint8_t> dq;\n        for (char c : seed) dq.push_back((uint8_t)ch2v(c));\n        int alt = 0;\n\n        while ((int)dq.size() < N) {\n            auto [sl, cl] = best_extend_char(dq, true);\n            auto [sr, cr] = best_extend_char(dq, false);\n\n            int side;\n            if (mode == 0) {\n                if (sl > sr) side = 0;\n                else if (sr > sl) side = 1;\n                else side = (rng() & 1);\n            } else if (mode == 1) {\n                side = 1;\n            } else if (mode == 2) {\n                side = 0;\n            } else {\n                side = (alt++ & 1);\n                if (max(sl, sr) >= 2 * min(sl, sr) + 10) side = (sl > sr ? 0 : 1);\n            }\n\n            if (side == 0) dq.push_front(cl);\n            else dq.push_back(cr);\n        }\n\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = dq[i];\n        return row;\n    }\n\n    int overlap_suffix_prefix_deque_pat(const deque<uint8_t>& dq, const string& p) const {\n        int lim = min<int>({11, (int)dq.size(), (int)p.size()});\n        for (int t = lim; t >= 1; --t) {\n            bool ok = true;\n            for (int i = 0; i < t; ++i) {\n                if (dq[(int)dq.size() - t + i] != (uint8_t)ch2v(p[i])) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return t;\n        }\n        return 0;\n    }\n\n    int overlap_suffix_prefix_pat_deque(const string& p, const deque<uint8_t>& dq) const {\n        int lim = min<int>({11, (int)dq.size(), (int)p.size()});\n        for (int t = lim; t >= 1; --t) {\n            bool ok = true;\n            for (int i = 0; i < t; ++i) {\n                if ((uint8_t)ch2v(p[(int)p.size() - t + i]) != dq[i]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return t;\n        }\n        return 0;\n    }\n\n    bool choose_best_overlap_right(const deque<uint8_t>& dq, int& best_id, int& best_ov, int& best_score) const {\n        best_id = -1;\n        best_ov = 0;\n        best_score = -1;\n        for (int id = 0; id < K; ++id) {\n            int ov = overlap_suffix_prefix_deque_pat(dq, pats[id].s);\n            if (ov <= 0 || ov >= pats[id].len) continue;\n            int sc = ov * 10000 + pats[id].weight * pats[id].len;\n            if (sc > best_score) best_score = sc, best_id = id, best_ov = ov;\n        }\n        return best_id != -1;\n    }\n\n    bool choose_best_overlap_left(const deque<uint8_t>& dq, int& best_id, int& best_ov, int& best_score) const {\n        best_id = -1;\n        best_ov = 0;\n        best_score = -1;\n        for (int id = 0; id < K; ++id) {\n            int ov = overlap_suffix_prefix_pat_deque(pats[id].s, dq);\n            if (ov <= 0 || ov >= pats[id].len) continue;\n            int sc = ov * 10000 + pats[id].weight * pats[id].len;\n            if (sc > best_score) best_score = sc, best_id = id, best_ov = ov;\n        }\n        return best_id != -1;\n    }\n\n    array<uint8_t, N> overlap_extend_from_seed(int seed_id, int mode) {\n        deque<uint8_t> dq;\n        for (char c : pats[seed_id].s) dq.push_back((uint8_t)ch2v(c));\n        int alt = 0;\n\n        while ((int)dq.size() < N) {\n            int lid, lov, lsc;\n            int rid, rov, rsc;\n            bool hasL = choose_best_overlap_left(dq, lid, lov, lsc);\n            bool hasR = choose_best_overlap_right(dq, rid, rov, rsc);\n\n            int side = 1;\n            if (mode == 0) {\n                if (!hasL && !hasR) side = (rng() & 1);\n                else if (!hasL) side = 1;\n                else if (!hasR) side = 0;\n                else if (lsc > rsc) side = 0;\n                else if (rsc > lsc) side = 1;\n                else side = (rng() & 1);\n            } else if (mode == 1) {\n                side = 1;\n                if (!hasR && hasL) side = 0;\n            } else if (mode == 2) {\n                side = 0;\n                if (!hasL && hasR) side = 1;\n            } else {\n                if (!hasL && !hasR) side = (rng() & 1);\n                else if (!hasL) side = 1;\n                else if (!hasR) side = 0;\n                else side = (alt++ & 1);\n            }\n\n            bool progressed = false;\n            if (side == 0 && hasL) {\n                const string& s = pats[lid].s;\n                for (int i = (int)s.size() - lov - 1; i >= 0 && (int)dq.size() < N; --i) {\n                    dq.push_front((uint8_t)ch2v(s[i]));\n                    progressed = true;\n                }\n            } else if (side == 1 && hasR) {\n                const string& s = pats[rid].s;\n                for (int i = rov; i < (int)s.size() && (int)dq.size() < N; ++i) {\n                    dq.push_back((uint8_t)ch2v(s[i]));\n                    progressed = true;\n                }\n            }\n\n            if (!progressed) {\n                auto [sl, cl] = best_extend_char(dq, true);\n                auto [sr, cr] = best_extend_char(dq, false);\n                if ((side == 0 && sl >= sr) || !hasR) dq.push_front(cl);\n                else dq.push_back(cr);\n            }\n        }\n\n        array<uint8_t, N> row{};\n        for (int i = 0; i < N; ++i) row[i] = dq[i];\n        return row;\n    }\n\n    void add_candidate(vector<Candidate>& pool, unordered_set<string>& used, const array<uint8_t, N>& row) {\n        string canon = canonical_row(row);\n        if (!used.insert(canon).second) return;\n        Candidate c;\n        c.row = row;\n        uint8_t seq[N];\n        for (int i = 0; i < N; ++i) seq[i] = row[i];\n        c.bits = compute_bits_seq(seq);\n        c.canon = canon;\n        pool.push_back(std::move(c));\n    }\n\n    vector<Candidate> generate_candidate_pool() {\n        vector<Candidate> pool;\n        unordered_set<string> used;\n        used.reserve(1024);\n\n        auto generate_with_scheme = [&](vector<int> residual, int rounds, int beamw) {\n            for (int t = 0; t < rounds; ++t) {\n                if (timer.elapsed() > 0.42) return;\n\n                vector<array<uint8_t, N>> cand_rows;\n                cand_rows.push_back(beam_search_row(residual, {}, beamw));\n\n                auto seeds = pick_seed_patterns(residual, 2, 1);\n                for (int id : seeds) {\n                    vector<uint8_t> pref;\n                    for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                    cand_rows.push_back(beam_search_row(residual, pref, beamw));\n                    cand_rows.push_back(transition_extend_from_seed(pats[id].s, 0));\n                    cand_rows.push_back(overlap_extend_from_seed(id, 0));\n                }\n\n                int best_gain = -1;\n                array<uint8_t, N> best_row{};\n                Bits best_bits{};\n\n                for (auto& row : cand_rows) {\n                    Bits bits{};\n                    int g = row_gain_and_bits(row, residual, bits);\n                    if (g > best_gain) {\n                        best_gain = g;\n                        best_row = row;\n                        best_bits = bits;\n                    }\n                }\n\n                add_candidate(pool, used, best_row);\n                for (int id = 0; id < K; ++id) if (getbit(best_bits, id)) residual[id] = 0;\n            }\n        };\n\n        vector<int> w1 = orig_weight;\n        generate_with_scheme(w1, 8, 120);\n\n        vector<int> w2(K);\n        for (int i = 0; i < K; ++i) w2[i] = orig_weight[i] * pats[i].len;\n        generate_with_scheme(w2, 8, 100);\n\n        vector<int> w3(K);\n        for (int i = 0; i < K; ++i) w3[i] = pats[i].len;\n        generate_with_scheme(w3, 6, 90);\n\n        vector<pair<int,int>> heavy;\n        for (int i = 0; i < K; ++i) heavy.push_back({orig_weight[i] * pats[i].len, i});\n        sort(heavy.begin(), heavy.end(), greater<pair<int,int>>());\n\n        for (int z = 0; z < min(12, (int)heavy.size()) && timer.elapsed() <= 0.52; ++z) {\n            int id = heavy[z].second;\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 0));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 1));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 2));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 0));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 1));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 2));\n        }\n\n        if (pool.empty()) add_candidate(pool, used, fallback_row(orig_weight));\n        return pool;\n    }\n\n    vector<Candidate> generate_targeted_pool(const MatrixState& ms, double stop_time) {\n        vector<int> w(K, 0);\n        for (int id = 0; id < K; ++id) {\n            if (ms.cnt[id] == 0) w[id] = orig_weight[id] * 6;\n            else if (ms.cnt[id] == 1) w[id] = orig_weight[id] * 3;\n            else if (ms.cnt[id] == 2) w[id] = orig_weight[id];\n        }\n\n        vector<Candidate> pool;\n        unordered_set<string> used;\n        used.reserve(256);\n\n        add_candidate(pool, used, beam_search_row(w, {}, 100));\n\n        auto seeds = pick_seed_patterns(w, 8, 2);\n        for (int id : seeds) {\n            if (timer.elapsed() > stop_time) break;\n\n            vector<uint8_t> pref;\n            for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n\n            add_candidate(pool, used, beam_search_row(w, pref, 90));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 0));\n            add_candidate(pool, used, transition_extend_from_seed(pats[id].s, 3));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 0));\n            add_candidate(pool, used, overlap_extend_from_seed(id, 3));\n        }\n\n        if (pool.empty()) add_candidate(pool, used, fallback_row(w));\n        return pool;\n    }\n\n    vector<array<uint8_t, N>> select_rows_trial(const vector<Candidate>& pool, int mode) {\n        vector<array<uint8_t, N>> rows;\n        vector<int> residual = orig_weight;\n        vector<int> used(pool.size(), 0);\n\n        for (int it = 0; it < N; ++it) {\n            int best = -1;\n            double best_score = -1e100;\n            for (int i = 0; i < (int)pool.size(); ++i) {\n                if (used[i]) continue;\n                int g = gain_by_bits(pool[i].bits, residual);\n                double score = g;\n                if (mode == 1) score += uniform_real_distribution<double>(0.0, 3.0)(rng);\n                if (mode == 2) score += uniform_real_distribution<double>(0.0, 10.0)(rng);\n                if (mode == 3) score += uniform_real_distribution<double>(0.0, 20.0)(rng);\n                if (score > best_score) {\n                    best_score = score;\n                    best = i;\n                }\n            }\n            if (best == -1 || best_score <= 0) {\n                auto row = fallback_row(residual);\n                rows.push_back(row);\n                Bits bits{};\n                row_gain_and_bits(row, residual, bits);\n                for (int id = 0; id < K; ++id) if (getbit(bits, id)) residual[id] = 0;\n            } else {\n                used[best] = 1;\n                rows.push_back(pool[best].row);\n                for (int id = 0; id < K; ++id) if (getbit(pool[best].bits, id)) residual[id] = 0;\n            }\n        }\n        return rows;\n    }\n\n    void init_matrix_state(MatrixState& ms, const vector<array<uint8_t, N>>& rows) {\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ms.a[r][c] = rows[r][c];\n\n        for (int r = 0; r < N; ++r) ms.row_bits[r] = compute_row_bits(ms, r);\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = compute_col_bits(ms, c);\n\n        ms.cnt.assign(K, 0);\n        for (int r = 0; r < N; ++r)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.row_bits[r], id)) ms.cnt[id]++;\n\n        for (int c = 0; c < N; ++c)\n            for (int id = 0; id < K; ++id)\n                if (getbit(ms.col_bits[c], id)) ms.cnt[id]++;\n\n        ms.score = 0;\n        for (int id = 0; id < K; ++id) if (ms.cnt[id] > 0) ms.score += orig_weight[id];\n    }\n\n    void transpose_state(MatrixState& ms) {\n        for (int i = 0; i < N; ++i)\n            for (int j = i + 1; j < N; ++j)\n                swap(ms.a[i][j], ms.a[j][i]);\n        swap(ms.row_bits, ms.col_bits);\n    }\n\n    vector<int> row_order_by_priority(const MatrixState& ms) {\n        vector<pair<long long, int>> v;\n        v.reserve(N);\n        for (int r = 0; r < N; ++r) {\n            long long pri = 0;\n            for (int id = 0; id < K; ++id) {\n                if (!getbit(ms.row_bits[r], id)) continue;\n                if (ms.cnt[id] == 1) pri += 4LL * orig_weight[id];\n                else if (ms.cnt[id] == 2) pri += 1LL * orig_weight[id];\n            }\n            pri = pri * 1000 + (long long)(rng() % 1000);\n            v.push_back({-pri, r});\n        }\n        sort(v.begin(), v.end());\n        vector<int> order;\n        order.reserve(N);\n        for (auto &p : v) order.push_back(p.second);\n        return order;\n    }\n\n    int eval_row_replace(const MatrixState& ms, int r,\n                         const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                         array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) seq[i] = (i == r ? new_row[c] : ms.a[i][c]);\n            new_cols[c] = compute_bits_seq(seq);\n        }\n\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_row_replace(MatrixState& ms, int r,\n                           const array<uint8_t, N>& new_row, const Bits& new_row_bits,\n                           const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(ms.row_bits[r], id);\n            after += (int)getbit(new_row_bits, id);\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n\n        for (int c = 0; c < N; ++c) ms.a[r][c] = new_row[c];\n        ms.row_bits[r] = new_row_bits;\n        for (int c = 0; c < N; ++c) ms.col_bits[c] = new_cols[c];\n        ms.score += delta;\n    }\n\n    bool same_exact_row(const MatrixState& ms, int r, const array<uint8_t, N>& row) const {\n        for (int c = 0; c < N; ++c) if (ms.a[r][c] != row[c]) return false;\n        return true;\n    }\n\n    bool improve_rows_from_pool(MatrixState& ms, const vector<Candidate>& pool, double time_limit) {\n        bool improved_any = false;\n        vector<int> order = row_order_by_priority(ms);\n\n        for (int idx = 0; idx < N; ++idx) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[idx];\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            auto test_base = [&](const array<uint8_t, N>& base_row, const Bits& base_bits) {\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base_row[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, base_bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = base_bits;\n                        best_cols = new_cols;\n                    }\n                }\n            };\n\n            for (const auto& cand : pool) test_base(cand.row, cand.bits);\n            for (int i = 0; i < N; ++i) {\n                array<uint8_t, N> cur{};\n                for (int c = 0; c < N; ++c) cur[c] = ms.a[i][c];\n                test_base(cur, ms.row_bits[i]);\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved_any = true;\n            }\n        }\n        return improved_any;\n    }\n\n    bool dynamic_rebuild_rows(MatrixState& ms, double time_limit) {\n        bool improved = false;\n        vector<int> order = row_order_by_priority(ms);\n\n        for (int ii = 0; ii < N; ++ii) {\n            if (timer.elapsed() > time_limit) break;\n            int r = order[ii];\n\n            vector<int> w(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) {\n                    w[id] = orig_weight[id] * 4;\n                } else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) {\n                    w[id] = orig_weight[id] * 3;\n                } else if (ms.cnt[id] == 2 && getbit(ms.row_bits[r], id)) {\n                    w[id] = orig_weight[id];\n                }\n            }\n\n            int sumw = 0;\n            for (int x : w) sumw += x;\n            if (sumw == 0) continue;\n\n            vector<array<uint8_t, N>> cand_rows;\n            cand_rows.push_back(beam_search_row(w, {}, 120));\n\n            auto seeds = pick_seed_patterns(w, 3, 1);\n            for (int id : seeds) {\n                vector<uint8_t> pref;\n                for (char c : pats[id].s) pref.push_back((uint8_t)ch2v(c));\n                cand_rows.push_back(beam_search_row(w, pref, 100));\n                cand_rows.push_back(transition_extend_from_seed(pats[id].s, 0));\n                cand_rows.push_back(overlap_extend_from_seed(id, 0));\n                cand_rows.push_back(overlap_extend_from_seed(id, 3));\n            }\n\n            vector<int> w2(K, 0);\n            for (int id = 0; id < K; ++id) {\n                if (ms.cnt[id] == 0) w2[id] = orig_weight[id];\n                else if (ms.cnt[id] == 1 && getbit(ms.row_bits[r], id)) w2[id] = orig_weight[id];\n            }\n            cand_rows.push_back(beam_search_row(w2, {}, 90));\n\n            int best_delta = 0;\n            array<uint8_t, N> best_row{};\n            Bits best_row_bits{};\n            array<Bits, N> best_cols{};\n\n            for (auto& base : cand_rows) {\n                Bits bits{};\n                uint8_t seq[N];\n                for (int c = 0; c < N; ++c) seq[c] = base[c];\n                bits = compute_bits_seq(seq);\n\n                for (int sh = 0; sh < N; ++sh) {\n                    array<uint8_t, N> row{};\n                    for (int c = 0; c < N; ++c) row[c] = base[(c + sh) % N];\n                    if (same_exact_row(ms, r, row)) continue;\n\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_replace(ms, r, row, bits, new_cols);\n                    if (delta > best_delta) {\n                        best_delta = delta;\n                        best_row = row;\n                        best_row_bits = bits;\n                        best_cols = new_cols;\n                    }\n                }\n            }\n\n            if (best_delta > 0) {\n                apply_row_replace(ms, r, best_row, best_row_bits, best_cols, best_delta);\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    int delta_replace_cols(const MatrixState& ms, const array<Bits, N>& new_cols) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            if ((before == 0) != (after == 0)) delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n        }\n        return delta;\n    }\n\n    void apply_replace_cols(MatrixState& ms, const array<Bits, N>& new_cols, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int c = 0; c < N; ++c) {\n                after -= (int)getbit(ms.col_bits[c], id);\n                after += (int)getbit(new_cols[c], id);\n            }\n            ms.cnt[id] = after;\n        }\n        ms.col_bits = new_cols;\n        ms.score += delta;\n    }\n\n    int delta_replace_rows(const MatrixState& ms, const array<Bits, N>& new_rows) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before;\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            if ((before == 0) != (after == 0)) delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n        }\n        return delta;\n    }\n\n    void apply_replace_rows(MatrixState& ms, const array<Bits, N>& new_rows, int delta) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            for (int r = 0; r < N; ++r) {\n                after -= (int)getbit(ms.row_bits[r], id);\n                after += (int)getbit(new_rows[r], id);\n            }\n            ms.cnt[id] = after;\n        }\n        ms.row_bits = new_rows;\n        ms.score += delta;\n    }\n\n    int eval_row_rotate(const MatrixState& ms, int r, int sh, array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                seq[i] = (i == r ? ms.a[r][(c + sh) % N] : ms.a[i][c]);\n            }\n            new_cols[c] = compute_bits_seq(seq);\n        }\n        return delta_replace_cols(ms, new_cols);\n    }\n\n    void apply_row_rotate(MatrixState& ms, int r, int sh, const array<Bits, N>& new_cols, int delta) {\n        array<uint8_t, N> old = ms.a[r], nw{};\n        for (int c = 0; c < N; ++c) nw[c] = old[(c + sh) % N];\n        ms.a[r] = nw;\n        apply_replace_cols(ms, new_cols, delta);\n    }\n\n    int eval_row_swap(const MatrixState& ms, int r1, int r2, array<Bits, N>& new_cols) const {\n        for (int c = 0; c < N; ++c) {\n            uint8_t seq[N];\n            for (int i = 0; i < N; ++i) {\n                if (i == r1) seq[i] = ms.a[r2][c];\n                else if (i == r2) seq[i] = ms.a[r1][c];\n                else seq[i] = ms.a[i][c];\n            }\n            new_cols[c] = compute_bits_seq(seq);\n        }\n        return delta_replace_cols(ms, new_cols);\n    }\n\n    void apply_row_swap(MatrixState& ms, int r1, int r2, const array<Bits, N>& new_cols, int delta) {\n        swap(ms.a[r1], ms.a[r2]);\n        swap(ms.row_bits[r1], ms.row_bits[r2]);\n        apply_replace_cols(ms, new_cols, delta);\n    }\n\n    int eval_col_rotate(const MatrixState& ms, int c, int sh, array<Bits, N>& new_rows) const {\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                seq[j] = (j == c ? ms.a[(r + sh) % N][c] : ms.a[r][j]);\n            }\n            new_rows[r] = compute_bits_seq(seq);\n        }\n        return delta_replace_rows(ms, new_rows);\n    }\n\n    void apply_col_rotate(MatrixState& ms, int c, int sh, const array<Bits, N>& new_rows, int delta) {\n        array<uint8_t, N> old{};\n        for (int r = 0; r < N; ++r) old[r] = ms.a[r][c];\n        for (int r = 0; r < N; ++r) ms.a[r][c] = old[(r + sh) % N];\n        apply_replace_rows(ms, new_rows, delta);\n    }\n\n    int eval_col_swap(const MatrixState& ms, int c1, int c2, array<Bits, N>& new_rows) const {\n        for (int r = 0; r < N; ++r) {\n            uint8_t seq[N];\n            for (int j = 0; j < N; ++j) {\n                if (j == c1) seq[j] = ms.a[r][c2];\n                else if (j == c2) seq[j] = ms.a[r][c1];\n                else seq[j] = ms.a[r][j];\n            }\n            new_rows[r] = compute_bits_seq(seq);\n        }\n        return delta_replace_rows(ms, new_rows);\n    }\n\n    void apply_col_swap(MatrixState& ms, int c1, int c2, const array<Bits, N>& new_rows, int delta) {\n        for (int r = 0; r < N; ++r) swap(ms.a[r][c1], ms.a[r][c2]);\n        swap(ms.col_bits[c1], ms.col_bits[c2]);\n        apply_replace_rows(ms, new_rows, delta);\n    }\n\n    void symmetry_hill_climb(MatrixState& ms, double time_limit) {\n        while (timer.elapsed() < time_limit) {\n            int best_delta = 0;\n            int best_type = -1, best_a = -1, best_b = -1;\n            array<Bits, N> best_lines{};\n\n            for (int r = 0; r < N; ++r) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_rotate(ms, r, sh, new_cols);\n                    if (delta > best_delta) best_delta = delta, best_type = 0, best_a = r, best_b = sh, best_lines = new_cols;\n                }\n            }\n\n            for (int r1 = 0; r1 < N; ++r1) {\n                for (int r2 = r1 + 1; r2 < N; ++r2) {\n                    array<Bits, N> new_cols;\n                    int delta = eval_row_swap(ms, r1, r2, new_cols);\n                    if (delta > best_delta) best_delta = delta, best_type = 1, best_a = r1, best_b = r2, best_lines = new_cols;\n                }\n            }\n\n            for (int c = 0; c < N; ++c) {\n                for (int sh = 1; sh < N; ++sh) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_rotate(ms, c, sh, new_rows);\n                    if (delta > best_delta) best_delta = delta, best_type = 2, best_a = c, best_b = sh, best_lines = new_rows;\n                }\n            }\n\n            for (int c1 = 0; c1 < N; ++c1) {\n                for (int c2 = c1 + 1; c2 < N; ++c2) {\n                    array<Bits, N> new_rows;\n                    int delta = eval_col_swap(ms, c1, c2, new_rows);\n                    if (delta > best_delta) best_delta = delta, best_type = 3, best_a = c1, best_b = c2, best_lines = new_rows;\n                }\n            }\n\n            if (best_delta <= 0) break;\n\n            if (best_type == 0) apply_row_rotate(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 1) apply_row_swap(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 2) apply_col_rotate(ms, best_a, best_b, best_lines, best_delta);\n            else if (best_type == 3) apply_col_swap(ms, best_a, best_b, best_lines, best_delta);\n        }\n    }\n\n    int calc_delta_two(const MatrixState& ms, const Bits& old1, const Bits& new1,\n                       const Bits& old2, const Bits& new2) const {\n        int delta = 0;\n        for (int id = 0; id < K; ++id) {\n            int before = ms.cnt[id];\n            int after = before\n                      - (int)getbit(old1, id)\n                      - (int)getbit(old2, id)\n                      + (int)getbit(new1, id)\n                      + (int)getbit(new2, id);\n            if ((before == 0) != (after == 0)) {\n                delta += (after > 0 ? orig_weight[id] : -orig_weight[id]);\n            }\n        }\n        return delta;\n    }\n\n    void apply_two(MatrixState& ms, const Bits& old1, const Bits& new1,\n                   const Bits& old2, const Bits& new2) {\n        for (int id = 0; id < K; ++id) {\n            int after = ms.cnt[id];\n            after -= (int)getbit(old1, id);\n            after -= (int)getbit(old2, id);\n            after += (int)getbit(new1, id);\n            after += (int)getbit(new2, id);\n            ms.cnt[id] = after;\n        }\n    }\n\n    void cell_local_search(MatrixState& ms, double time_limit) {\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        auto bestA = ms.a;\n        int bestScore = ms.score;\n\n        while (timer.elapsed() < time_limit) {\n            double prog = timer.elapsed() / time_limit;\n            double T = 1.2 * pow(0.02 / 1.2, prog);\n\n            int r = (int)(rng() % N);\n            int c = (int)(rng() % N);\n            uint8_t oldch = ms.a[r][c];\n\n            Bits oldR = ms.row_bits[r];\n            Bits oldC = ms.col_bits[c];\n\n            int best_delta = -1000000000;\n            uint8_t best_ch = oldch;\n            Bits bestR = oldR, bestC = oldC;\n\n            for (uint8_t ch = 0; ch < 8; ++ch) {\n                if (ch == oldch) continue;\n                ms.a[r][c] = ch;\n                Bits newR = compute_row_bits(ms, r);\n                Bits newC = compute_col_bits(ms, c);\n                int delta = calc_delta_two(ms, oldR, newR, oldC, newC);\n                if (delta > best_delta) {\n                    best_delta = delta;\n                    best_ch = ch;\n                    bestR = newR;\n                    bestC = newC;\n                }\n            }\n\n            bool accept = false;\n            if (best_delta >= 0) accept = true;\n            else if (urd(rng) < exp((double)best_delta / T)) accept = true;\n\n            if (accept && best_ch != oldch) {\n                ms.a[r][c] = best_ch;\n                apply_two(ms, oldR, bestR, oldC, bestC);\n                ms.row_bits[r] = bestR;\n                ms.col_bits[c] = bestC;\n                ms.score += best_delta;\n                if (ms.score > bestScore) {\n                    bestScore = ms.score;\n                    bestA = ms.a;\n                }\n            } else {\n                ms.a[r][c] = oldch;\n            }\n        }\n\n        ms.a = bestA;\n    }\n\n    vector<string> solve() {\n        int n;\n        cin >> n >> M;\n\n        array<unordered_map<uint64_t, int>, MAXL + 1> cnt_of;\n        for (int len = MINL; len <= MAXL; ++len) cnt_of[len].reserve(M * 2);\n\n        for (int i = 0; i < M; ++i) {\n            string s;\n            cin >> s;\n            cnt_of[(int)s.size()][encode_string(s)]++;\n        }\n\n        pats.clear();\n        for (int len = MINL; len <= MAXL; ++len) {\n            id_of[len].clear();\n            id_of[len].reserve(cnt_of[len].size() * 2 + 1);\n            for (auto& kv : cnt_of[len]) {\n                Pattern p;\n                p.len = len;\n                p.code = kv.first;\n                p.weight = kv.second;\n                p.s = decode_string(kv.first, len);\n                int id = (int)pats.size();\n                pats.push_back(std::move(p));\n                id_of[len][kv.first] = id;\n            }\n        }\n\n        K = (int)pats.size();\n        orig_weight.assign(K, 0);\n        for (int i = 0; i < K; ++i) orig_weight[i] = pats[i].weight;\n\n        build_ac();\n        build_transition_stats();\n\n        auto pool = generate_candidate_pool();\n\n        MatrixState best_ms;\n        int best_init_score = -1;\n\n        for (int trial = 0; trial < 5; ++trial) {\n            auto rows = select_rows_trial(pool, trial);\n            MatrixState ms;\n            init_matrix_state(ms, rows);\n            if (ms.score > best_init_score) {\n                best_init_score = ms.score;\n                best_ms = ms;\n            }\n        }\n\n        MatrixState ms = best_ms;\n\n        if (timer.elapsed() < 0.95) improve_rows_from_pool(ms, pool, 0.95);\n        if (timer.elapsed() < 1.40) dynamic_rebuild_rows(ms, 1.40);\n\n        if (timer.elapsed() < 1.75) {\n            transpose_state(ms);\n            improve_rows_from_pool(ms, pool, 1.75);\n        }\n        if (timer.elapsed() < 2.00) {\n            dynamic_rebuild_rows(ms, 2.00);\n            transpose_state(ms);\n        } else {\n            transpose_state(ms);\n        }\n\n        if (timer.elapsed() < 2.22) {\n            auto tpool = generate_targeted_pool(ms, 2.16);\n            improve_rows_from_pool(ms, tpool, 2.22);\n        }\n\n        if (timer.elapsed() < 2.42) {\n            transpose_state(ms);\n            auto tpool2 = generate_targeted_pool(ms, 2.36);\n            improve_rows_from_pool(ms, tpool2, 2.42);\n            transpose_state(ms);\n        }\n\n        if (timer.elapsed() < 2.72) symmetry_hill_climb(ms, 2.72);\n        if (timer.elapsed() < 2.88) dynamic_rebuild_rows(ms, 2.88);\n        if (timer.elapsed() < 2.93) symmetry_hill_climb(ms, 2.93);\n        if (timer.elapsed() < 2.95 && ms.score < M) cell_local_search(ms, 2.95);\n\n        vector<string> ans(N, string(N, 'A'));\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < N; ++c)\n                ans[r][c] = v2ch(ms.a[r][c]);\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    auto ans = solver.solve();\n    for (auto& s : ans) cout << s << '\\n';\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\n\nstruct Dinic {\n    struct Edge {\n        int to, rev;\n        ll cap;\n    };\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic() {}\n    Dinic(int n) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, ll 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\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();\n            q.pop();\n            for (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\n    ll dfs(int v, int t, ll 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[v] >= level[e.to]) continue;\n            ll d = dfs(e.to, t, min(f, e.cap));\n            if (d <= 0) continue;\n            e.cap -= d;\n            g[e.to][e.rev].cap += d;\n            return d;\n        }\n        return 0;\n    }\n\n    ll maxflow(int s, int t) {\n        ll flow = 0;\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n            while (true) {\n                ll f = dfs(s, t, INF64);\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n\n    vector<char> reachable_from(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();\n            q.pop();\n            for (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 MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow() {}\n    MinCostFlow(int n) : n(n), g(n) {}\n\n    int add_edge(int fr, int to, int cap, ll cost) {\n        int idx = (int)g[fr].size();\n        g[fr].push_back({to, (int)g[to].size(), cap, cost});\n        g[to].push_back({fr, idx, 0, -cost});\n        return idx;\n    }\n\n    ll min_cost_negative_paths(int s, int t) {\n        ll total = 0;\n        while (true) {\n            vector<ll> dist(n, INF64);\n            vector<int> pv(n, -1), pe(n, -1);\n            vector<char> inq(n, 0);\n            queue<int> q;\n            dist[s] = 0;\n            q.push(s);\n            inq[s] = 1;\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                inq[v] = 0;\n                for (int i = 0; i < (int)g[v].size(); i++) {\n                    auto &e = g[v][i];\n                    if (e.cap <= 0) continue;\n                    ll nd = dist[v] + e.cost;\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        if (!inq[e.to]) {\n                            inq[e.to] = 1;\n                            q.push(e.to);\n                        }\n                    }\n                }\n            }\n            if (dist[t] == INF64 || dist[t] >= 0) break;\n            int f = 1;\n            for (int v = t; v != s; v = pv[v]) {\n                auto &e = g[pv[v]][pe[v]];\n                f = min(f, e.cap);\n            }\n            for (int v = t; v != s; v = pv[v]) {\n                auto &e = g[pv[v]][pe[v]];\n                e.cap -= f;\n                g[v][e.rev].cap += f;\n            }\n            total += dist[t] * f;\n        }\n        return total;\n    }\n};\n\nstruct Watch {\n    // 0 = pair(H,V), 1 = H only, 2 = V only\n    int type;\n    int h, v;\n    int cell;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, si, sj;\n    cin >> N >> si >> sj;\n    vector<string> c(N);\n    for (int i = 0; i < N; i++) cin >> c[i];\n\n    vector<vector<int>> cellId(N, vector<int>(N, -1));\n    vector<int> rr, cc, enterCost;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (c[i][j] != '#') {\n                cellId[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                enterCost.push_back(c[i][j] - '0');\n            }\n        }\n    }\n    int M = (int)rr.size();\n    int startCell = cellId[si][sj];\n\n    vector<vector<int>> nbr(M);\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (0 <= ni && ni < N && 0 <= nj && nj < N && cellId[ni][nj] != -1) {\n                nbr[id].push_back(cellId[ni][nj]);\n            }\n        }\n    }\n\n    auto dijkstra = [&](int src, bool reverse, bool needPrev) {\n        vector<ll> dist(M, INF64);\n        vector<int> prev(needPrev ? M : 0, -1);\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n        while (!pq.empty()) {\n            auto [cd, u] = pq.top();\n            pq.pop();\n            if (cd != dist[u]) continue;\n            for (int v : nbr[u]) {\n                ll w = reverse ? enterCost[u] : enterCost[v];\n                ll nd = cd + w;\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (needPrev) prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n        return pair<vector<ll>, vector<int>>(move(dist), move(prev));\n    };\n\n    auto [distFromStart, _s0] = dijkstra(startCell, false, false);\n    auto [distToStart, _s1] = dijkstra(startCell, true, false);\n\n    vector<vector<int>> hSeg(N, vector<int>(N, -1));\n    vector<vector<int>> vSeg(N, vector<int>(N, -1));\n    int Hcnt = 0, Vcnt = 0;\n\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (c[i][j] == '#') {\n                j++;\n                continue;\n            }\n            int k = j;\n            while (k < N && c[i][k] != '#') {\n                hSeg[i][k] = Hcnt;\n                k++;\n            }\n            Hcnt++;\n            j = k;\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (c[i][j] == '#') {\n                i++;\n                continue;\n            }\n            int k = i;\n            while (k < N && c[k][j] != '#') {\n                vSeg[k][j] = Vcnt;\n                k++;\n            }\n            Vcnt++;\n            i = k;\n        }\n    }\n\n    vector<int> cellH(M), cellV(M);\n    vector<vector<int>> cellsOfH(Hcnt), cellsOfV(Vcnt);\n    vector<vector<int>> adjV(Hcnt);\n    for (int id = 0; id < M; id++) {\n        int i = rr[id], j = cc[id];\n        int h = hSeg[i][j];\n        int v = vSeg[i][j];\n        cellH[id] = h;\n        cellV[id] = v;\n        cellsOfH[h].push_back(id);\n        cellsOfV[v].push_back(id);\n        adjV[h].push_back(v);\n    }\n\n    int startH = cellH[startCell];\n    int startV = cellV[startCell];\n\n    auto cellRoundTrip = [&](int id) -> ll {\n        return distFromStart[id] + distToStart[id];\n    };\n\n    vector<ll> wH(Hcnt, INF64), wV(Vcnt, INF64);\n    for (int id = 0; id < M; id++) {\n        ll w = cellRoundTrip(id);\n        wH[cellH[id]] = min(wH[cellH[id]], w);\n        wV[cellV[id]] = min(wV[cellV[id]], w);\n    }\n    wH[startH] = 0;\n    wV[startV] = 0;\n\n    vector<char> selH(Hcnt, 0), selV(Vcnt, 0);\n    {\n        int S = Hcnt + Vcnt;\n        int T = S + 1;\n        Dinic mf(Hcnt + Vcnt + 2);\n        ll sumW = 0;\n        for (int h = 0; h < Hcnt; h++) {\n            mf.add_edge(S, h, wH[h]);\n            sumW += wH[h];\n        }\n        for (int v = 0; v < Vcnt; v++) {\n            mf.add_edge(Hcnt + v, T, wV[v]);\n            sumW += wV[v];\n        }\n        ll BIG = max<ll>((ll)1e15, sumW + 1);\n        for (int h = 0; h < Hcnt; h++) {\n            for (int v : adjV[h]) mf.add_edge(h, Hcnt + v, BIG);\n        }\n        mf.maxflow(S, T);\n        vector<char> reach = mf.reachable_from(S);\n        for (int h = 0; h < Hcnt; h++) selH[h] = !reach[h];\n        for (int v = 0; v < Vcnt; v++) selV[v] = reach[Hcnt + v];\n    }\n\n    vector<char> needH = selH, needV = selV;\n    needH[startH] = 0;\n    needV[startV] = 0;\n\n    vector<int> mapH(Hcnt, -1), revH;\n    vector<int> mapV(Vcnt, -1), revV;\n    for (int h = 0; h < Hcnt; h++) if (needH[h]) {\n        mapH[h] = (int)revH.size();\n        revH.push_back(h);\n    }\n    for (int v = 0; v < Vcnt; v++) if (needV[v]) {\n        mapV[v] = (int)revV.size();\n        revV.push_back(v);\n    }\n\n    int nH = (int)revH.size();\n    int nV = (int)revV.size();\n\n    vector<ll> bestSingleHCost(Hcnt, INF64), bestSingleVCost(Vcnt, INF64);\n    vector<int> bestSingleHCell(Hcnt, -1), bestSingleVCell(Vcnt, -1);\n\n    for (int h : revH) {\n        for (int id : cellsOfH[h]) {\n            ll w = cellRoundTrip(id);\n            if (w < bestSingleHCost[h]) {\n                bestSingleHCost[h] = w;\n                bestSingleHCell[h] = id;\n            }\n        }\n    }\n    for (int v : revV) {\n        for (int id : cellsOfV[v]) {\n            ll w = cellRoundTrip(id);\n            if (w < bestSingleVCost[v]) {\n                bestSingleVCost[v] = w;\n                bestSingleVCell[v] = id;\n            }\n        }\n    }\n\n    vector<Watch> watches;\n    struct PairEdgeInfo { int hnode, edgeIdx, ih, iv, cell; };\n    vector<PairEdgeInfo> pairEdges;\n\n    if (nH > 0 && nV > 0) {\n        int S = 0;\n        int hBase = 1;\n        int vBase = hBase + nH;\n        int T = vBase + nV;\n        MinCostFlow mcf(T + 1);\n\n        for (int ih = 0; ih < nH; ih++) mcf.add_edge(S, hBase + ih, 1, 0);\n        for (int iv = 0; iv < nV; iv++) mcf.add_edge(vBase + iv, T, 1, 0);\n\n        for (int id = 0; id < M; id++) {\n            int h = cellH[id], v = cellV[id];\n            int ih = mapH[h], iv = mapV[v];\n            if (ih == -1 || iv == -1) continue;\n            ll saving = bestSingleHCost[h] + bestSingleVCost[v] - cellRoundTrip(id);\n            if (saving <= 0) continue;\n            int hnode = hBase + ih;\n            int vnode = vBase + iv;\n            int eidx = mcf.add_edge(hnode, vnode, 1, -saving);\n            pairEdges.push_back({hnode, eidx, ih, iv, id});\n        }\n\n        mcf.min_cost_negative_paths(S, T);\n\n        vector<char> matchedH(nH, 0), matchedV(nV, 0);\n        for (auto &pe : pairEdges) {\n            auto &e = mcf.g[pe.hnode][pe.edgeIdx];\n            if (e.cap == 0) {\n                int h = revH[pe.ih];\n                int v = revV[pe.iv];\n                watches.push_back({0, h, v, pe.cell});\n                matchedH[pe.ih] = 1;\n                matchedV[pe.iv] = 1;\n            }\n        }\n\n        for (int ih = 0; ih < nH; ih++) if (!matchedH[ih]) {\n            int h = revH[ih];\n            if (bestSingleHCell[h] != -1) watches.push_back({1, h, -1, bestSingleHCell[h]});\n        }\n        for (int iv = 0; iv < nV; iv++) if (!matchedV[iv]) {\n            int v = revV[iv];\n            if (bestSingleVCell[v] != -1) watches.push_back({2, -1, v, bestSingleVCell[v]});\n        }\n    }\n\n    int W = (int)watches.size();\n\n    vector<int> cntSelH(Hcnt, 0), cntSelV(Vcnt, 0);\n    if (selH[startH]) cntSelH[startH]++;\n    if (selV[startV]) cntSelV[startV]++;\n    for (auto &w : watches) {\n        if (w.type == 0) {\n            if (selH[w.h]) cntSelH[w.h]++;\n            if (selV[w.v]) cntSelV[w.v]++;\n        } else if (w.type == 1) {\n            if (selH[w.h]) cntSelH[w.h]++;\n        } else {\n            if (selV[w.v]) cntSelV[w.v]++;\n        }\n    }\n\n    vector<int> ordW(W);\n    iota(ordW.begin(), ordW.end(), 0);\n    sort(ordW.begin(), ordW.end(), [&](int a, int b) {\n        ll wa = cellRoundTrip(watches[a].cell), wb = cellRoundTrip(watches[b].cell);\n        if (wa != wb) return wa > wb;\n        if (rr[watches[a].cell] != rr[watches[b].cell]) return rr[watches[a].cell] < rr[watches[b].cell];\n        return cc[watches[a].cell] < cc[watches[b].cell];\n    });\n\n    vector<char> alive(W, 1);\n    for (int idx : ordW) {\n        auto &w = watches[idx];\n        bool ok = true;\n        if (w.type == 0) {\n            if (selH[w.h] && cntSelH[w.h] <= 1) ok = false;\n            if (selV[w.v] && cntSelV[w.v] <= 1) ok = false;\n        } else if (w.type == 1) {\n            if (selH[w.h] && cntSelH[w.h] <= 1) ok = false;\n        } else {\n            if (selV[w.v] && cntSelV[w.v] <= 1) ok = false;\n        }\n        if (ok) {\n            alive[idx] = 0;\n            if (w.type == 0) {\n                if (selH[w.h]) cntSelH[w.h]--;\n                if (selV[w.v]) cntSelV[w.v]--;\n            } else if (w.type == 1) {\n                if (selH[w.h]) cntSelH[w.h]--;\n            } else {\n                if (selV[w.v]) cntSelV[w.v]--;\n            }\n        }\n    }\n\n    vector<Watch> filtered;\n    for (int i = 0; i < W; i++) if (alive[i]) filtered.push_back(watches[i]);\n    watches.swap(filtered);\n    W = (int)watches.size();\n\n    vector<int> baseRelCells;\n    baseRelCells.push_back(startCell);\n    for (auto &w : watches) baseRelCells.push_back(w.cell);\n    int R = (int)baseRelCells.size();\n\n    vector<vector<ll>> baseDistFromAll(R, vector<ll>(M));\n    vector<vector<ll>> baseDistToAll(R, vector<ll>(M));\n    vector<vector<int>> basePrevs(R, vector<int>(M, -1));\n    vector<vector<ll>> baseDistMat(R, vector<ll>(R, INF64));\n\n    for (int s = 0; s < R; s++) {\n        auto [df, prev] = dijkstra(baseRelCells[s], false, true);\n        auto [dr, _x] = dijkstra(baseRelCells[s], true, false);\n        baseDistFromAll[s] = move(df);\n        baseDistToAll[s] = move(dr);\n        basePrevs[s] = move(prev);\n    }\n    for (int s = 0; s < R; s++) {\n        for (int t = 0; t < R; t++) {\n            baseDistMat[s][t] = baseDistFromAll[s][baseRelCells[t]];\n        }\n    }\n\n    auto cycleCostWith = [&](const vector<int>& cyc, const vector<vector<ll>>& distMat) -> ll {\n        ll ret = 0;\n        int sz = (int)cyc.size();\n        for (int i = 0; i < sz; i++) ret += distMat[cyc[i]][cyc[(i + 1) % sz]];\n        return ret;\n    };\n\n    auto validate_path = [&](const vector<int>& path) -> bool {\n        if (path.empty()) return false;\n        if (path.front() != startCell || path.back() != startCell) return false;\n        for (int i = 1; i < (int)path.size(); i++) {\n            int a = path[i - 1], b = path[i];\n            if (abs(rr[a] - rr[b]) + abs(cc[a] - cc[b]) != 1) return false;\n        }\n        vector<char> seenH(Hcnt, 0), seenV(Vcnt, 0);\n        for (int x : path) {\n            seenH[cellH[x]] = 1;\n            seenV[cellV[x]] = 1;\n        }\n        for (int id = 0; id < M; id++) {\n            if (!seenH[cellH[id]] && !seenV[cellV[id]]) return false;\n        }\n        return true;\n    };\n\n    auto pathCost = [&](const vector<int>& path) -> ll {\n        ll ret = 0;\n        for (int i = 1; i < (int)path.size(); i++) ret += enterCost[path[i]];\n        return ret;\n    };\n\n    auto build_initial_cheapest_insertion = [&](const vector<vector<ll>>& distMat) -> vector<int> {\n        if (R == 1) return vector<int>{0};\n        vector<int> cyc;\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestInit = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll val = distMat[0][i] + distMat[i][0];\n            if (val < bestInit) {\n                bestInit = val;\n                first = i;\n            }\n        }\n        cyc = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            ll bestDelta = INF64;\n            int bestNode = -1, bestPos = -1;\n            int sz = (int)cyc.size();\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                for (int pos = 0; pos < sz; pos++) {\n                    int a = cyc[pos];\n                    int b = cyc[(pos + 1) % sz];\n                    ll delta = distMat[a][x] + distMat[x][b] - distMat[a][b];\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestNode = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            used[bestNode] = 1;\n            cyc.insert(cyc.begin() + bestPos + 1, bestNode);\n        }\n        return cyc;\n    };\n\n    auto build_initial_nearest_neighbor = [&](const vector<vector<ll>>& distMat) -> vector<int> {\n        vector<int> cyc = {0};\n        if (R == 1) return cyc;\n        vector<char> used(R, 0);\n        used[0] = 1;\n        int cur = 0;\n        for (int step = 1; step < R; step++) {\n            int best = -1;\n            ll bestVal = INF64;\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                ll val = distMat[cur][x];\n                if (val < bestVal) {\n                    bestVal = val;\n                    best = x;\n                }\n            }\n            used[best] = 1;\n            cyc.push_back(best);\n            cur = best;\n        }\n        return cyc;\n    };\n\n    auto build_initial_nearest_return = [&](const vector<vector<ll>>& distMat) -> vector<int> {\n        vector<int> cyc = {0};\n        if (R == 1) return cyc;\n        vector<char> used(R, 0);\n        used[0] = 1;\n        int cur = 0;\n        for (int step = 1; step < R; step++) {\n            int best = -1;\n            ll bestVal = INF64;\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                ll val = distMat[cur][x] + distMat[x][0];\n                if (val < bestVal) {\n                    bestVal = val;\n                    best = x;\n                }\n            }\n            used[best] = 1;\n            cyc.push_back(best);\n            cur = best;\n        }\n        return cyc;\n    };\n\n    auto build_initial_farthest_insertion = [&](const vector<vector<ll>>& distMat) -> vector<int> {\n        if (R == 1) return vector<int>{0};\n        vector<int> cyc;\n        vector<char> used(R, 0);\n        int first = 1;\n        ll bestFar = distMat[0][1] + distMat[1][0];\n        for (int i = 2; i < R; i++) {\n            ll val = distMat[0][i] + distMat[i][0];\n            if (val > bestFar) {\n                bestFar = val;\n                first = i;\n            }\n        }\n        cyc = {0, first};\n        used[0] = used[first] = 1;\n\n        for (int cnt = 2; cnt < R; cnt++) {\n            int choose = -1;\n            ll chooseScore = -1;\n            for (int x = 1; x < R; x++) if (!used[x]) {\n                ll mind = INF64;\n                for (int u : cyc) mind = min(mind, distMat[u][x] + distMat[x][u]);\n                if (mind > chooseScore) {\n                    chooseScore = mind;\n                    choose = x;\n                }\n            }\n            int bestPos = -1;\n            ll bestDelta = INF64;\n            int sz = (int)cyc.size();\n            for (int pos = 0; pos < sz; pos++) {\n                int a = cyc[pos];\n                int b = cyc[(pos + 1) % sz];\n                ll delta = distMat[a][choose] + distMat[choose][b] - distMat[a][b];\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = pos;\n                }\n            }\n            used[choose] = 1;\n            cyc.insert(cyc.begin() + bestPos + 1, choose);\n        }\n        return cyc;\n    };\n\n    auto build_initial_angle = [&](bool revOrd) -> vector<int> {\n        vector<pair<pair<double, ll>, int>> ord;\n        for (int i = 1; i < R; i++) {\n            int cell = baseRelCells[i];\n            double ang = atan2((double)rr[cell] - si, (double)cc[cell] - sj);\n            ll rad = 1LL * (rr[cell] - si) * (rr[cell] - si) + 1LL * (cc[cell] - sj) * (cc[cell] - sj);\n            ord.push_back({{ang, rad}, i});\n        }\n        sort(ord.begin(), ord.end(), [&](auto &a, auto &b) {\n            if (a.first.first != b.first.first) return a.first.first < b.first.first;\n            return a.first.second < b.first.second;\n        });\n        vector<int> cyc = {0};\n        if (revOrd) {\n            for (int i = (int)ord.size() - 1; i >= 0; i--) cyc.push_back(ord[i].second);\n        } else {\n            for (auto &e : ord) cyc.push_back(e.second);\n        }\n        return cyc;\n    };\n\n    auto build_initial_start_sorted = [&](bool desc) -> vector<int> {\n        vector<pair<ll,int>> ord;\n        for (int i = 1; i < R; i++) {\n            ord.push_back({baseDistMat[0][i] + baseDistMat[i][0], i});\n        }\n        sort(ord.begin(), ord.end());\n        if (desc) reverse(ord.begin(), ord.end());\n        vector<int> cyc = {0};\n        for (auto &e : ord) cyc.push_back(e.second);\n        return cyc;\n    };\n\n    auto reverse_cycle = [&](const vector<int>& cyc) {\n        vector<int> rev = {0};\n        for (int i = (int)cyc.size() - 1; i >= 1; i--) rev.push_back(cyc[i]);\n        return rev;\n    };\n\n    auto shorten_full_path = [&](vector<int>& path) {\n        auto path_full_covered = [&](const vector<int>& cntH2, const vector<int>& cntV2,\n                                     const vector<int>& touchedCells) -> bool {\n            for (int cell : touchedCells) {\n                if (cntH2[cellH[cell]] == 0 && cntV2[cellV[cell]] == 0) return false;\n            }\n            return true;\n        };\n\n        vector<int> cntPathH(Hcnt, 0), cntPathV(Vcnt, 0);\n        for (int cell : path) {\n            cntPathH[cellH[cell]]++;\n            cntPathV[cellV[cell]]++;\n        }\n\n        vector<int> markH(Hcnt, -1), markV(Vcnt, -1), markCell(M, -1);\n        vector<int> decH(Hcnt, 0), decV(Vcnt, 0);\n        int stamp2 = 0;\n        const int OCC_CHECKS = 16;\n\n        while (true) {\n            int L = (int)path.size();\n            if (L <= 1) break;\n\n            vector<ll> pref(L, 0);\n            for (int i = 1; i < L; i++) pref[i] = pref[i - 1] + enterCost[path[i]];\n\n            vector<vector<int>> occ(M);\n            ll bestSave = 0;\n            int bestL = -1, bestR = -1;\n\n            for (int p = 0; p < L; p++) {\n                int cell = path[p];\n                auto &vec = occ[cell];\n\n                int checks = 0;\n                for (int z = (int)vec.size() - 1; z >= 0 && checks < OCC_CHECKS; z--, checks++) {\n                    int l = vec[z];\n                    if (p <= l) continue;\n                    ll save = pref[p] - pref[l];\n                    if (save <= bestSave) continue;\n\n                    stamp2++;\n                    vector<int> touchedHs, touchedVs, touchedCells;\n\n                    for (int q = l + 1; q <= p; q++) {\n                        int x = path[q];\n                        int h = cellH[x], v = cellV[x];\n\n                        if (markH[h] != stamp2) {\n                            markH[h] = stamp2;\n                            decH[h] = 0;\n                            touchedHs.push_back(h);\n                        }\n                        if (markV[v] != stamp2) {\n                            markV[v] = stamp2;\n                            decV[v] = 0;\n                            touchedVs.push_back(v);\n                        }\n                        decH[h]++;\n                        decV[v]++;\n\n                        if (markCell[x] != stamp2) {\n                            markCell[x] = stamp2;\n                            touchedCells.push_back(x);\n                        }\n                    }\n\n                    for (int h : touchedHs) cntPathH[h] -= decH[h];\n                    for (int v : touchedVs) cntPathV[v] -= decV[v];\n\n                    for (int h : touchedHs) {\n                        for (int cell2 : cellsOfH[h]) {\n                            if (markCell[cell2] != stamp2) {\n                                markCell[cell2] = stamp2;\n                                touchedCells.push_back(cell2);\n                            }\n                        }\n                    }\n                    for (int v : touchedVs) {\n                        for (int cell2 : cellsOfV[v]) {\n                            if (markCell[cell2] != stamp2) {\n                                markCell[cell2] = stamp2;\n                                touchedCells.push_back(cell2);\n                            }\n                        }\n                    }\n\n                    bool ok = path_full_covered(cntPathH, cntPathV, touchedCells);\n\n                    for (int h : touchedHs) cntPathH[h] += decH[h];\n                    for (int v : touchedVs) cntPathV[v] += decV[v];\n\n                    if (ok) {\n                        bestSave = save;\n                        bestL = l;\n                        bestR = p;\n                    }\n                }\n\n                vec.push_back(p);\n            }\n\n            if (bestSave <= 0) break;\n\n            for (int q = bestL + 1; q <= bestR; q++) {\n                int x = path[q];\n                cntPathH[cellH[x]]--;\n                cntPathV[cellV[x]]--;\n            }\n            path.erase(path.begin() + bestL + 1, path.begin() + bestR + 1);\n        }\n    };\n\n    auto process_cycle = [&](vector<int> cyc, bool routeAwareRelocate) -> vector<int> {\n        vector<int> relCellsLocal = baseRelCells;\n        vector<vector<ll>> distMatLocal = baseDistMat;\n        vector<vector<int>> prevsLocal = basePrevs;\n\n        auto recompute_local_data = [&]() {\n            int RR2 = (int)relCellsLocal.size();\n            distMatLocal.assign(RR2, vector<ll>(RR2, INF64));\n            prevsLocal.assign(RR2, vector<int>(M, -1));\n            for (int s = 0; s < RR2; s++) {\n                auto [distF, prev] = dijkstra(relCellsLocal[s], false, true);\n                prevsLocal[s] = move(prev);\n                for (int t = 0; t < RR2; t++) distMatLocal[s][t] = distF[relCellsLocal[t]];\n            }\n        };\n\n        auto pre_local_search = [&](vector<int>& cycRef, const vector<vector<ll>>& distMat) {\n            if ((int)cycRef.size() <= 2) return;\n            for (int phase = 0; phase < 3; phase++) {\n                bool improved = true;\n                while (improved) {\n                    improved = false;\n                    int sz = (int)cycRef.size();\n\n                    for (int len = 1; len <= 3 && !improved; len++) {\n                        if (len >= sz) break;\n                        for (int i = 1; i + len - 1 < sz && !improved; i++) {\n                            int k = i + len - 1;\n                            int a = cycRef[i - 1];\n                            int x1 = cycRef[i];\n                            int xk = cycRef[k];\n                            int b = cycRef[(k + 1) % sz];\n\n                            for (int j = 0; j < sz && !improved; j++) {\n                                if (j >= i - 1 && j <= k) continue;\n                                int c1 = cycRef[j];\n                                int d1 = cycRef[(j + 1) % sz];\n                                ll delta =\n                                    distMat[a][b] + distMat[c1][x1] + distMat[xk][d1]\n                                    - distMat[a][x1] - distMat[xk][b] - distMat[c1][d1];\n                                if (delta < 0) {\n                                    vector<int> block(cycRef.begin() + i, cycRef.begin() + k + 1);\n                                    cycRef.erase(cycRef.begin() + i, cycRef.begin() + k + 1);\n                                    int pos = (j < i ? j + 1 : j - len + 1);\n                                    cycRef.insert(cycRef.begin() + pos, block.begin(), block.end());\n                                    improved = true;\n                                }\n                            }\n                        }\n                    }\n                    if (improved) continue;\n\n                    sz = (int)cycRef.size();\n                    ll curCost = cycleCostWith(cycRef, distMat);\n                    for (int i = 1; i < sz && !improved; i++) {\n                        for (int j = i + 1; j < sz && !improved; j++) {\n                            vector<int> nc = cycRef;\n                            swap(nc[i], nc[j]);\n                            ll ncCost = cycleCostWith(nc, distMat);\n                            if (ncCost < curCost) {\n                                cycRef.swap(nc);\n                                curCost = ncCost;\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n            }\n        };\n\n        auto reseat_waypoints = [&](const vector<int>& cycRef) -> bool {\n            if ((int)cycRef.size() <= 2) return false;\n\n            vector<char> needIdx(R, 0);\n            for (int idx : cycRef) needIdx[idx] = 1;\n\n            vector<vector<ll>> distFromIdx(R), distToIdx(R);\n            for (int idx = 0; idx < R; idx++) if (needIdx[idx]) {\n                auto [df, _a] = dijkstra(relCellsLocal[idx], false, false);\n                auto [dr, _b] = dijkstra(relCellsLocal[idx], true, false);\n                distFromIdx[idx] = move(df);\n                distToIdx[idx] = move(dr);\n            }\n\n            bool changed = false;\n            int sz = (int)cycRef.size();\n            for (int pos = 1; pos < sz; pos++) {\n                int idx = cycRef[pos];\n                Watch &w = watches[idx - 1];\n                if (w.type == 0) continue;\n\n                int pidx = cycRef[(pos - 1 + sz) % sz];\n                int nidx = cycRef[(pos + 1) % sz];\n\n                int bestCell = relCellsLocal[idx];\n                ll bestVal = distFromIdx[pidx][bestCell] + distToIdx[nidx][bestCell];\n\n                if (w.type == 1) {\n                    for (int cand : cellsOfH[w.h]) {\n                        ll val = distFromIdx[pidx][cand] + distToIdx[nidx][cand];\n                        if (val < bestVal) {\n                            bestVal = val;\n                            bestCell = cand;\n                        }\n                    }\n                } else {\n                    for (int cand : cellsOfV[w.v]) {\n                        ll val = distFromIdx[pidx][cand] + distToIdx[nidx][cand];\n                        if (val < bestVal) {\n                            bestVal = val;\n                            bestCell = cand;\n                        }\n                    }\n                }\n\n                if (bestCell != relCellsLocal[idx]) {\n                    relCellsLocal[idx] = bestCell;\n                    changed = true;\n                }\n            }\n            return changed;\n        };\n\n        pre_local_search(cyc, distMatLocal);\n\n        if (routeAwareRelocate) {\n            for (int it = 0; it < 3; it++) {\n                bool ch = reseat_waypoints(cyc);\n                if (!ch) break;\n                recompute_local_data();\n                pre_local_search(cyc, distMatLocal);\n            }\n        }\n\n        vector<vector<int>> arcHs, arcVs;\n\n        auto rebuild_arc_data = [&]() {\n            int RRl = (int)relCellsLocal.size();\n            arcHs.assign(RRl * RRl, {});\n            arcVs.assign(RRl * RRl, {});\n            vector<int> seenH2(Hcnt, -1), seenV2(Vcnt, -1);\n            int stampLocal = 0;\n\n            for (int s = 0; s < RRl; s++) {\n                for (int t = 0; t < RRl; t++) {\n                    int idx = s * RRl + t;\n                    stampLocal++;\n\n                    vector<int> pathCells;\n                    int srcCell = relCellsLocal[s];\n                    int dstCell = relCellsLocal[t];\n                    pathCells.push_back(srcCell);\n                    if (srcCell != dstCell) {\n                        vector<int> rev;\n                        int cur = dstCell;\n                        while (cur != srcCell) {\n                            int p = prevsLocal[s][cur];\n                            if (p == -1) break;\n                            rev.push_back(cur);\n                            cur = p;\n                        }\n                        reverse(rev.begin(), rev.end());\n                        for (int x : rev) pathCells.push_back(x);\n                    }\n\n                    auto &hs = arcHs[idx];\n                    auto &vs = arcVs[idx];\n                    for (int cell : pathCells) {\n                        int h = cellH[cell], v = cellV[cell];\n                        if (seenH2[h] != stampLocal) {\n                            seenH2[h] = stampLocal;\n                            hs.push_back(h);\n                        }\n                        if (seenV2[v] != stampLocal) {\n                            seenV2[v] = stampLocal;\n                            vs.push_back(v);\n                        }\n                    }\n                }\n            }\n        };\n\n        rebuild_arc_data();\n\n        auto add_arc_cov = [&](vector<int>& cntH2, vector<int>& cntV2, int a, int b, int delta) {\n            int RRl = (int)relCellsLocal.size();\n            int idx = a * RRl + b;\n            for (int h : arcHs[idx]) cntH2[h] += delta;\n            for (int v : arcVs[idx]) cntV2[v] += delta;\n        };\n\n        auto full_covered_local = [&](const vector<int>& cntH2, const vector<int>& cntV2) -> bool {\n            for (int id = 0; id < M; id++) {\n                if (cntH2[cellH[id]] == 0 && cntV2[cellV[id]] == 0) return false;\n            }\n            return true;\n        };\n\n        auto cycle_is_covered_local = [&](const vector<int>& cycRef) -> bool {\n            vector<int> cntH2(Hcnt, 0), cntV2(Vcnt, 0);\n            int sz = (int)cycRef.size();\n            for (int i = 0; i < sz; i++) {\n                add_arc_cov(cntH2, cntV2, cycRef[i], cycRef[(i + 1) % sz], +1);\n            }\n            return full_covered_local(cntH2, cntV2);\n        };\n\n        auto delete_waypoints = [&](vector<int>& cycRef) {\n            vector<int> covH(Hcnt, 0), covV(Vcnt, 0);\n            int sz = (int)cycRef.size();\n            for (int i = 0; i < sz; i++) add_arc_cov(covH, covV, cycRef[i], cycRef[(i + 1) % sz], +1);\n\n            while ((int)cycRef.size() > 1) {\n                sz = (int)cycRef.size();\n                int bestPos = -1;\n                ll bestDelta = 0;\n\n                for (int pos = 1; pos < sz; pos++) {\n                    int a = cycRef[(pos - 1 + sz) % sz];\n                    int b = cycRef[pos];\n                    int c2 = cycRef[(pos + 1) % sz];\n                    ll delta = distMatLocal[a][c2] - distMatLocal[a][b] - distMatLocal[b][c2];\n\n                    add_arc_cov(covH, covV, a, b, -1);\n                    add_arc_cov(covH, covV, b, c2, -1);\n                    add_arc_cov(covH, covV, a, c2, +1);\n\n                    bool ok = full_covered_local(covH, covV);\n\n                    add_arc_cov(covH, covV, a, c2, -1);\n                    add_arc_cov(covH, covV, a, b, +1);\n                    add_arc_cov(covH, covV, b, c2, +1);\n\n                    if (ok && delta < bestDelta) {\n                        bestDelta = delta;\n                        bestPos = pos;\n                    }\n                }\n\n                if (bestPos == -1) break;\n\n                int a = cycRef[(bestPos - 1 + (int)cycRef.size()) % (int)cycRef.size()];\n                int b = cycRef[bestPos];\n                int c2 = cycRef[(bestPos + 1) % (int)cycRef.size()];\n\n                add_arc_cov(covH, covV, a, b, -1);\n                add_arc_cov(covH, covV, b, c2, -1);\n                add_arc_cov(covH, covV, a, c2, +1);\n\n                cycRef.erase(cycRef.begin() + bestPos);\n            }\n        };\n\n        auto post_local_search_safe = [&](vector<int>& cycRef) {\n            if ((int)cycRef.size() <= 2) return;\n            int sz0 = (int)cycRef.size();\n            int maxIter = (sz0 <= 35 ? 7 : (sz0 <= 60 ? 5 : 3));\n\n            for (int iter = 0; iter < maxIter; iter++) {\n                ll curCost = cycleCostWith(cycRef, distMatLocal);\n                ll bestDelta = 0;\n                vector<int> bestCycle;\n                int sz = (int)cycRef.size();\n\n                int maxLen = (sz <= 30 ? 3 : (sz <= 50 ? 2 : 1));\n                for (int len = 1; len <= maxLen; len++) {\n                    for (int i = 1; i + len - 1 < sz; i++) {\n                        int k = i + len - 1;\n                        int a = cycRef[i - 1];\n                        int x1 = cycRef[i];\n                        int xk = cycRef[k];\n                        int b = cycRef[(k + 1) % sz];\n\n                        for (int after = 0; after < sz; after++) {\n                            if (after >= i - 1 && after <= k) continue;\n                            int c1 = cycRef[after];\n                            int d1 = cycRef[(after + 1) % sz];\n                            ll delta =\n                                distMatLocal[a][b] + distMatLocal[c1][x1] + distMatLocal[xk][d1]\n                                - distMatLocal[a][x1] - distMatLocal[xk][b] - distMatLocal[c1][d1];\n                            if (delta >= bestDelta) continue;\n\n                            vector<int> nc = cycRef;\n                            vector<int> block(nc.begin() + i, nc.begin() + k + 1);\n                            nc.erase(nc.begin() + i, nc.begin() + k + 1);\n                            int pos = after;\n                            if (after > k) pos -= len;\n                            nc.insert(nc.begin() + pos + 1, block.begin(), block.end());\n\n                            if (!cycle_is_covered_local(nc)) continue;\n                            bestDelta = delta;\n                            bestCycle.swap(nc);\n                        }\n                    }\n                }\n\n                for (int i = 1; i < sz; i++) {\n                    for (int j = i + 1; j < sz; j++) {\n                        vector<int> nc = cycRef;\n                        swap(nc[i], nc[j]);\n                        ll delta = cycleCostWith(nc, distMatLocal) - curCost;\n                        if (delta >= bestDelta) continue;\n                        if (!cycle_is_covered_local(nc)) continue;\n                        bestDelta = delta;\n                        bestCycle.swap(nc);\n                    }\n                }\n\n                if (sz <= 70) {\n                    for (int i = 1; i < sz; i++) {\n                        for (int j = i + 1; j < sz; j++) {\n                            vector<int> nc = cycRef;\n                            reverse(nc.begin() + i, nc.begin() + j + 1);\n                            ll delta = cycleCostWith(nc, distMatLocal) - curCost;\n                            if (delta >= bestDelta) continue;\n                            if (!cycle_is_covered_local(nc)) continue;\n                            bestDelta = delta;\n                            bestCycle.swap(nc);\n                        }\n                    }\n                }\n\n                if (bestDelta < 0) cycRef.swap(bestCycle);\n                else break;\n            }\n        };\n\n        int reps = routeAwareRelocate ? 3 : 2;\n        for (int rep = 0; rep < reps; rep++) {\n            delete_waypoints(cyc);\n            if (routeAwareRelocate) {\n                bool ch = reseat_waypoints(cyc);\n                if (ch) {\n                    recompute_local_data();\n                    rebuild_arc_data();\n                }\n            }\n            post_local_search_safe(cyc);\n            if (routeAwareRelocate) {\n                bool ch = reseat_waypoints(cyc);\n                if (ch) {\n                    recompute_local_data();\n                    rebuild_arc_data();\n                }\n            }\n        }\n        delete_waypoints(cyc);\n\n        if (routeAwareRelocate) {\n            bool ch = reseat_waypoints(cyc);\n            if (ch) {\n                recompute_local_data();\n                rebuild_arc_data();\n                post_local_search_safe(cyc);\n                delete_waypoints(cyc);\n            }\n        }\n\n        vector<int> safePath;\n        safePath.push_back(startCell);\n        for (int idx = 0; idx < (int)cyc.size(); idx++) {\n            int s = cyc[idx];\n            int t = cyc[(idx + 1) % cyc.size()];\n            int sCell = relCellsLocal[s];\n            int tCell = relCellsLocal[t];\n            if (sCell == tCell) continue;\n\n            vector<int> rev;\n            int cur = tCell;\n            while (cur != sCell) {\n                int p = prevsLocal[s][cur];\n                if (p == -1) break;\n                rev.push_back(cur);\n                cur = p;\n            }\n            reverse(rev.begin(), rev.end());\n            for (int x : rev) safePath.push_back(x);\n        }\n\n        if (!validate_path(safePath)) return safePath;\n\n        vector<int> path = safePath;\n        shorten_full_path(path);\n        if (!validate_path(path)) return safePath;\n        return path;\n    };\n\n    vector<vector<int>> initCycles;\n    initCycles.push_back(build_initial_cheapest_insertion(baseDistMat));\n    if (R >= 2) {\n        initCycles.push_back(build_initial_nearest_neighbor(baseDistMat));\n        initCycles.push_back(build_initial_nearest_return(baseDistMat));\n        initCycles.push_back(build_initial_farthest_insertion(baseDistMat));\n        initCycles.push_back(build_initial_angle(false));\n        initCycles.push_back(build_initial_angle(true));\n        initCycles.push_back(build_initial_start_sorted(false));\n        initCycles.push_back(build_initial_start_sorted(true));\n    }\n\n    vector<vector<int>> allCycles;\n    for (auto &cyc : initCycles) {\n        allCycles.push_back(cyc);\n        if ((int)cyc.size() >= 2) allCycles.push_back(reverse_cycle(cyc));\n    }\n\n    vector<vector<int>> uniqueCycles;\n    for (auto &cyc : allCycles) {\n        bool dup = false;\n        for (auto &u : uniqueCycles) {\n            if (u == cyc) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniqueCycles.push_back(cyc);\n    }\n\n    vector<pair<ll,int>> ranked;\n    for (int i = 0; i < (int)uniqueCycles.size(); i++) {\n        ranked.push_back({cycleCostWith(uniqueCycles[i], baseDistMat), i});\n    }\n    sort(ranked.begin(), ranked.end());\n\n    vector<vector<int>> candidatePaths;\n\n    for (auto cyc : uniqueCycles) {\n        auto path = process_cycle(cyc, false);\n        if (validate_path(path)) candidatePaths.push_back(move(path));\n    }\n\n    int extraK = min<int>(8, ranked.size());\n    for (int t = 0; t < extraK; t++) {\n        auto path = process_cycle(uniqueCycles[ranked[t].second], true);\n        if (validate_path(path)) candidatePaths.push_back(move(path));\n    }\n\n    if (candidatePaths.empty()) {\n        cout << \"\" << '\\n';\n        return 0;\n    }\n\n    int bestIdx = 0;\n    ll bestCost = pathCost(candidatePaths[0]);\n    for (int i = 1; i < (int)candidatePaths.size(); i++) {\n        ll cur = pathCost(candidatePaths[i]);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestIdx = i;\n        }\n    }\n\n    vector<int> bestPath = candidatePaths[bestIdx];\n\n    auto dirChar = [&](int a, int b) -> char {\n        int ra = rr[a], ca = cc[a];\n        int rb = rr[b], cb = cc[b];\n        if (rb == ra - 1 && cb == ca) return 'U';\n        if (rb == ra + 1 && cb == ca) return 'D';\n        if (rb == ra && cb == ca - 1) return 'L';\n        return 'R';\n    };\n\n    string ans;\n    for (int i = 1; i < (int)bestPath.size(); i++) {\n        ans.push_back(dirChar(bestPath[i - 1], bestPath[i]));\n    }\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 1000;\n\nstruct Observation {\n    int task;\n    int t;\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>> children(N), parents(N);\n    for (int i = 0; i < R; ++i) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        children[u].push_back(v);\n        parents[v].push_back(u);\n    }\n\n    // ----------------------------\n    // Precompute task statistics\n    // ----------------------------\n    vector<int> indeg(N), rem_pre(N), outdeg(N, 0), sumd(N, 0);\n    vector<int> maxd(K, 0);\n    vector<double> avgd(K, 0.0);\n\n    for (int i = 0; i < N; ++i) {\n        indeg[i] = (int)parents[i].size();\n        rem_pre[i] = indeg[i];\n        outdeg[i] = (int)children[i].size();\n        for (int k = 0; k < K; ++k) {\n            sumd[i] += d[i][k];\n            maxd[k] = max(maxd[k], d[i][k]);\n            avgd[k] += d[i][k];\n        }\n    }\n    for (int k = 0; k < K; ++k) avgd[k] /= N;\n\n    // Initial skill guess\n    vector<int> init_skill(K);\n    for (int k = 0; k < K; ++k) {\n        int v = (int)llround(avgd[k] * 1.6);\n        v = max(0, min(v, maxd[k]));\n        init_skill[k] = v;\n    }\n\n    // Descendant count by bitset DP\n    vector<bitset<MAXN>> reach(N);\n    vector<int> desc_cnt(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        for (int ch : children[i]) {\n            reach[i] |= reach[ch];\n            reach[i].set(ch);\n        }\n        desc_cnt[i] = (int)reach[i].count();\n    }\n\n    // Weighted bottom level\n    vector<long long> bottom(N, 0);\n    for (int i = N - 1; i >= 0; --i) {\n        long long best_child = 0;\n        for (int ch : children[i]) best_child = max(best_child, bottom[ch]);\n        long long node_w = sumd[i] + 5;\n        bottom[i] = node_w + best_child;\n    }\n\n    vector<long long> base_priority(N, 0);\n    for (int i = 0; i < N; ++i) {\n        base_priority[i] =\n            bottom[i] * 30LL +\n            desc_cnt[i] * 5LL +\n            outdeg[i] * 20LL +\n            sumd[i];\n    }\n\n    auto calc_w_with_skill = [&](int task, const vector<int>& skill) -> int {\n        int w = 0;\n        for (int k = 0; k < K; ++k) {\n            if (d[task][k] > skill[k]) w += d[task][k] - skill[k];\n        }\n        return w;\n    };\n\n    vector<int> default_w(N), default_t(N);\n    for (int i = 0; i < N; ++i) {\n        default_w[i] = calc_w_with_skill(i, init_skill);\n        default_t[i] = max(1, default_w[i]);\n    }\n\n    // ----------------------------\n    // Online state\n    // ----------------------------\n    // -1: not started, 0: in progress, 1: completed\n    vector<int> task_status(N, -1);\n\n    vector<int> current_task(M, -1);\n    vector<int> start_day(M, -1);\n\n    vector<vector<int>> skill_hat(M, init_skill);\n    vector<vector<Observation>> obs(M);\n\n    auto loss_interval = [&](int w, int t) -> double {\n        int L, U;\n        if (t <= 1) {\n            // t=1 can happen for w up to 4\n            L = 0;\n            U = 4;\n        } else {\n            L = max(0, t - 3);\n            U = t + 3;\n        }\n\n        double dist = 0.0;\n        if (w < L) dist = (double)(L - w);\n        else if (w > U) dist = (double)(w - U);\n        else dist = 0.0;\n\n        double weight = (t <= 1 ? 1.0 : 1.0 + 0.05 * min(t, 20));\n        return dist * dist * weight;\n    };\n\n    auto optimize_member = [&](int j) {\n        int T = (int)obs[j].size();\n        if (T == 0) return;\n\n        vector<int>& s = skill_hat[j];\n        vector<int> curW(T);\n        for (int idx = 0; idx < T; ++idx) {\n            curW[idx] = calc_w_with_skill(obs[j][idx].task, s);\n        }\n\n        const int max_iter = 3;\n        for (int it = 0; it < max_iter; ++it) {\n            bool changed = false;\n\n            for (int k = 0; k < K; ++k) {\n                int prev = s[k];\n\n                vector<int> base(T);\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    base[idx] = curW[idx] - max(0, d[task][k] - prev);\n                }\n\n                double best_obj = 1e100;\n                int best_x = prev;\n                int best_tie1 = 0;\n                int best_tie2 = abs(prev - init_skill[k]);\n\n                for (int x = 0; x <= maxd[k]; ++x) {\n                    double obj = 0.0;\n                    for (int idx = 0; idx < T; ++idx) {\n                        int task = obs[j][idx].task;\n                        int w = base[idx] + max(0, d[task][k] - x);\n                        obj += loss_interval(w, obs[j][idx].t);\n                    }\n\n                    obj += 0.02 * (x - init_skill[k]) * (x - init_skill[k]);\n\n                    int tie1 = abs(x - prev);\n                    int tie2 = abs(x - init_skill[k]);\n                    if (obj + 1e-9 < best_obj ||\n                        (abs(obj - best_obj) <= 1e-9 &&\n                         (tie1 < best_tie1 || (tie1 == best_tie1 && tie2 < best_tie2)))) {\n                        best_obj = obj;\n                        best_x = x;\n                        best_tie1 = tie1;\n                        best_tie2 = tie2;\n                    }\n                }\n\n                if (best_x != prev) changed = true;\n                s[k] = best_x;\n\n                for (int idx = 0; idx < T; ++idx) {\n                    int task = obs[j][idx].task;\n                    curW[idx] = base[idx] + max(0, d[task][k] - best_x);\n                }\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto estimate_time = [&](int member, int task) -> double {\n        double trust = (double)obs[member].size() / ((double)obs[member].size() + 5.0);\n        int learned_w = calc_w_with_skill(task, skill_hat[member]);\n        double p = (1.0 - trust) * default_w[task] + trust * learned_w;\n        p += (1.0 - trust) * 0.10 * default_w[task];\n        return max(1.0, p);\n    };\n\n    auto get_ready_tasks = [&]() -> vector<int> {\n        vector<int> ready;\n        ready.reserve(N);\n        for (int i = 0; i < N; ++i) {\n            if (task_status[i] == -1 && rem_pre[i] == 0) ready.push_back(i);\n        }\n        return ready;\n    };\n\n    auto calc_unlock_bonus = [&](int task) -> pair<int, long long> {\n        int cnt = 0;\n        long long child_bottom_sum = 0;\n        for (int ch : children[task]) {\n            if (task_status[ch] == -1 && rem_pre[ch] == 1) {\n                ++cnt;\n                child_bottom_sum += bottom[ch];\n            }\n        }\n        return {cnt, child_bottom_sum};\n    };\n\n    auto dynamic_priority = [&](int task) -> long long {\n        auto [cnt, child_sum] = calc_unlock_bonus(task);\n        return base_priority[task] + 400LL * cnt + child_sum * 8LL;\n    };\n\n    auto select_candidates = [&](const vector<int>& ready, int free_cnt) -> vector<int> {\n        int limit = max(80, free_cnt * 6);\n        if ((int)ready.size() <= limit) return ready;\n\n        vector<pair<long long,int>> by_pri;\n        vector<pair<int,int>> by_easy;\n        vector<pair<long long,int>> by_unlock;\n\n        by_pri.reserve(ready.size());\n        by_easy.reserve(ready.size());\n        by_unlock.reserve(ready.size());\n\n        for (int t : ready) {\n            auto [cnt, child_sum] = calc_unlock_bonus(t);\n            by_pri.push_back({dynamic_priority(t), t});\n            by_easy.push_back({default_t[t], t});\n            by_unlock.push_back({(long long)cnt * 1000000LL + child_sum, t});\n        }\n\n        sort(by_pri.begin(), by_pri.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n        sort(by_easy.begin(), by_easy.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first < b.first;\n            return a.second < b.second;\n        });\n        sort(by_unlock.begin(), by_unlock.end(), [&](auto& a, auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int take_pri = max(30, free_cnt * 3);\n        int take_easy = max(20, free_cnt * 2);\n        int take_unlock = max(20, free_cnt * 2);\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(limit + 10);\n\n        for (int i = 0; i < (int)by_pri.size() && (int)cand.size() < take_pri; ++i) {\n            int t = by_pri[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_easy.size() && i < take_easy; ++i) {\n            int t = by_easy[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (int i = 0; i < (int)by_unlock.size() && i < take_unlock; ++i) {\n            int t = by_unlock[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n        for (auto &p : by_pri) {\n            if ((int)cand.size() >= limit) break;\n            int t = p.second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        return cand;\n    };\n\n    auto decide_assignments = [&]() -> vector<pair<int,int>> {\n        vector<int> free_members;\n        for (int j = 0; j < M; ++j) {\n            if (current_task[j] == -1) free_members.push_back(j);\n        }\n\n        vector<int> ready = get_ready_tasks();\n        if (free_members.empty() || ready.empty()) return {};\n\n        vector<int> cand = select_candidates(ready, (int)free_members.size());\n\n        int F = (int)free_members.size();\n        int C = (int)cand.size();\n\n        vector<long long> pri(C);\n        vector<int> unlock_cnt(C);\n        for (int ci = 0; ci < C; ++ci) {\n            auto [cnt, _] = calc_unlock_bonus(cand[ci]);\n            pri[ci] = dynamic_priority(cand[ci]);\n            unlock_cnt[ci] = cnt;\n        }\n\n        vector<vector<double>> pred(F, vector<double>(C));\n        vector<double> best_t(C, 1e100);\n\n        for (int fi = 0; fi < F; ++fi) {\n            int mem = free_members[fi];\n            for (int ci = 0; ci < C; ++ci) {\n                pred[fi][ci] = estimate_time(mem, cand[ci]);\n                best_t[ci] = min(best_t[ci], pred[fi][ci]);\n            }\n        }\n\n        const long long TIME_PENALTY = 850;\n        const long long GAP_PENALTY = 250;\n        const long long UNKNOWN_LONG_PENALTY = 35;\n        const long long UNKNOWN_UNLOCK_PENALTY = 120;\n\n        vector<char> used_f(F, 0), used_c(C, 0);\n        vector<pair<int,int>> ret;\n        ret.reserve(min(F, C));\n\n        for (int step = 0; step < min(F, C); ++step) {\n            long long best_score = LLONG_MIN;\n            int best_f = -1, best_c = -1;\n            long long best_pri = LLONG_MIN;\n            double best_et = 1e100;\n            int best_unlock = -1;\n\n            for (int fi = 0; fi < F; ++fi) if (!used_f[fi]) {\n                int mem = free_members[fi];\n                int seen = (int)obs[mem].size();\n\n                for (int ci = 0; ci < C; ++ci) if (!used_c[ci]) {\n                    double et = pred[fi][ci];\n                    double gap = et - best_t[ci];\n\n                    long long score = pri[ci]\n                        - (long long)llround(et * TIME_PENALTY)\n                        - (long long)llround(gap * GAP_PENALTY);\n\n                    if (seen < 4) {\n                        double extra = max(0.0, et - 8.0) * (4 - seen);\n                        score -= (long long)llround(extra * UNKNOWN_LONG_PENALTY);\n                    }\n\n                    if (seen < 3 && unlock_cnt[ci] > 0) {\n                        score -= 1LL * (3 - seen) * unlock_cnt[ci] * UNKNOWN_UNLOCK_PENALTY;\n                    }\n\n                    bool better = false;\n                    if (score > best_score) better = true;\n                    else if (score == best_score) {\n                        if (pri[ci] > best_pri) better = true;\n                        else if (pri[ci] == best_pri) {\n                            if (et + 1e-9 < best_et) better = true;\n                            else if (abs(et - best_et) <= 1e-9) {\n                                if (unlock_cnt[ci] > best_unlock) better = true;\n                                else if (unlock_cnt[ci] == best_unlock) {\n                                    if (best_c == -1 || cand[ci] < cand[best_c]) better = true;\n                                }\n                            }\n                        }\n                    }\n\n                    if (better) {\n                        best_score = score;\n                        best_f = fi;\n                        best_c = ci;\n                        best_pri = pri[ci];\n                        best_et = et;\n                        best_unlock = unlock_cnt[ci];\n                    }\n                }\n            }\n\n            if (best_f == -1) break;\n            used_f[best_f] = 1;\n            used_c[best_c] = 1;\n            ret.emplace_back(free_members[best_f], cand[best_c]);\n        }\n\n        return ret;\n    };\n\n    // ----------------------------\n    // Interactive loop\n    // ----------------------------\n    int day = 0;\n    while (true) {\n        ++day;\n\n        vector<pair<int,int>> assigns = decide_assignments();\n\n        for (auto [mem, task] : assigns) {\n            task_status[task] = 0;\n            current_task[mem] = task;\n            start_day[mem] = day;\n        }\n\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) {\n            cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        }\n        cout << '\\n' << flush;\n\n        int nfin;\n        cin >> nfin;\n        if (!cin) return 0;\n        if (nfin == -1) return 0;\n\n        vector<int> finished(nfin);\n        for (int i = 0; i < nfin; ++i) {\n            cin >> finished[i];\n            --finished[i];\n        }\n\n        for (int mem : finished) {\n            int task = current_task[mem];\n            if (task == -1) continue;\n\n            int duration = day - start_day[mem] + 1;\n            obs[mem].push_back({task, duration});\n\n            task_status[task] = 1;\n            current_task[mem] = -1;\n            start_day[mem] = -1;\n\n            for (int ch : children[task]) {\n                --rem_pre[ch];\n            }\n\n            optimize_member(mem);\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 1000;\nstatic constexpr int TOT = 2001; // 0: office, 1..1000 pickup, 1001..2000 delivery\nstatic constexpr double TL = 1.90;\nstatic constexpr int NLIST = 5;\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 XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Insertion {\n    int delta;\n    int g1, g2;\n};\n\nstruct SingleInsertion {\n    int delta;\n    int g;\n};\n\nstruct State {\n    vector<int> seq;\n    vector<char> selected;\n    int cost = 0;\n};\n\nint X[TOT], Y[TOT];\nvector<int> DM;\n\nint d0p_[N + 1], dpd_[N + 1], dd0_[N + 1];\nint baseScore[N + 1];\nvector<vector<int>> order_lists;\n\ninline int dist_node(int a, int b) {\n    return DM[a * TOT + b];\n}\ninline int pickup_node(int id) { return id; }\ninline int delivery_node(int id) { return N + id; }\n\nint route_cost(const vector<int>& seq) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)seq.size(); i++) s += dist_node(seq[i], seq[i + 1]);\n    return s;\n}\n\nvector<int> get_selected_ids(const vector<char>& selected) {\n    vector<int> ids;\n    ids.reserve(50);\n    for (int id = 1; id <= N; id++) if (selected[id]) ids.push_back(id);\n    return ids;\n}\n\nInsertion find_best_insertion(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    const int m = (int)seq.size();\n\n    Insertion best{INT_MAX, -1, -1};\n\n    for (int g1 = 0; g1 < m - 1; g1++) {\n        int a = seq[g1], b = seq[g1 + 1];\n        int dab = dist_node(a, b);\n\n        int delta_same = dist_node(a, u) + dist_node(u, v) + dist_node(v, b) - dab;\n        if (delta_same < best.delta) best = {delta_same, g1, g1};\n\n        int delta_pick = dist_node(a, u) + dist_node(u, b) - dab;\n        for (int g2 = g1 + 1; g2 < m - 1; g2++) {\n            int c = seq[g2], d = seq[g2 + 1];\n            int delta = delta_pick + dist_node(c, v) + dist_node(v, d) - dist_node(c, d);\n            if (delta < best.delta) best = {delta, g1, g2};\n        }\n    }\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& seq, int id, const Insertion& ins) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() + 2);\n\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == ins.g1) {\n            res.push_back(u);\n            if (ins.g2 == ins.g1) res.push_back(v);\n        }\n        if (i == ins.g2 && ins.g2 > ins.g1) {\n            res.push_back(v);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order(const vector<int>& seq, int id) {\n    const int u = pickup_node(id);\n    const int v = delivery_node(id);\n    vector<int> res;\n    res.reserve(seq.size() - 2);\n    for (int x : seq) {\n        if (x != u && x != v) res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> remove_orders(const vector<int>& seq, const vector<int>& rem_ids) {\n    vector<char> bad(N + 1, 0);\n    for (int id : rem_ids) bad[id] = 1;\n    vector<int> res;\n    res.reserve(seq.size() - 2 * (int)rem_ids.size());\n    for (int x : seq) {\n        if (x == 0) {\n            res.push_back(x);\n        } else {\n            int id = (x <= N ? x : x - N);\n            if (!bad[id]) res.push_back(x);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_node_once(const vector<int>& seq, int node) {\n    vector<int> res;\n    res.reserve(seq.size() - 1);\n    bool skipped = false;\n    for (int x : seq) {\n        if (!skipped && x == node) {\n            skipped = true;\n            continue;\n        }\n        res.push_back(x);\n    }\n    return res;\n}\n\nvector<int> insert_single_node(const vector<int>& seq, int node, int g) {\n    vector<int> res;\n    res.reserve(seq.size() + 1);\n    for (int i = 0; i < (int)seq.size(); i++) {\n        res.push_back(seq[i]);\n        if (i == g) res.push_back(node);\n    }\n    return res;\n}\n\nSingleInsertion find_best_single_insertion(const vector<int>& seq, int node, int gl, int gr) {\n    int m = (int)seq.size();\n    gl = max(gl, 0);\n    gr = min(gr, m - 2);\n\n    SingleInsertion best{INT_MAX, -1};\n    for (int g = gl; g <= gr; g++) {\n        int a = seq[g], b = seq[g + 1];\n        int delta = dist_node(a, node) + dist_node(node, b) - dist_node(a, b);\n        if (delta < best.delta) best = {delta, g};\n    }\n    return best;\n}\n\nint pick_rcl_index(int sz, XorShift64& rng) {\n    if (sz <= 1) return 0;\n    int r = rng.next_int(0, 99);\n    if (sz == 2) return (r < 72 ? 0 : 1);\n    if (sz == 3) return (r < 55 ? 0 : (r < 85 ? 1 : 2));\n    if (sz == 4) return (r < 45 ? 0 : (r < 73 ? 1 : (r < 90 ? 2 : 3)));\n    if (sz == 5) return (r < 42 ? 0 : (r < 68 ? 1 : (r < 84 ? 2 : (r < 94 ? 3 : 4))));\n    return (r < 40 ? 0 : (r < 64 ? 1 : (r < 79 ? 2 : (r < 89 ? 3 : (r < 96 ? 4 : 5)))));\n}\n\nstruct Cand {\n    int delta;\n    int id;\n    Insertion ins;\n};\n\nvoid push_top_k(vector<Cand>& top, const Cand& c, int topK) {\n    if ((int)top.size() < topK) {\n        top.push_back(c);\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            return baseScore[a.id] < baseScore[b.id];\n        });\n    } else {\n        const auto& w = top.back();\n        if (c.delta < w.delta || (c.delta == w.delta && baseScore[c.id] < baseScore[w.id])) {\n            top.back() = c;\n            sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n                if (a.delta != b.delta) return a.delta < b.delta;\n                return baseScore[a.id] < baseScore[b.id];\n            });\n        }\n    }\n}\n\n// mode 0: pure main list\n// mode 1: anchored mix = 2/3 main + 1/3 sub\n// mode 2: pure sub list\nvector<Cand> collect_top_insertions_mode(\n    const vector<int>& seq,\n    const vector<char>& selected,\n    int main_lid,\n    int sub_lid,\n    int mode,\n    int limit_ids,\n    int topK,\n    const Timer* timer = nullptr,\n    double end_time = 1e100\n) {\n    vector<Cand> top;\n    top.reserve(topK);\n    vector<char> used(N + 1, 0);\n\n    auto scan_list = [&](int lid, int lim) {\n        lim = min(lim, (int)order_lists[lid].size());\n        for (int i = 0; i < lim; i++) {\n            if (timer && timer->elapsed() >= end_time) break;\n            int id = order_lists[lid][i];\n            if (selected[id] || used[id]) continue;\n            used[id] = 1;\n            Insertion ins = find_best_insertion(seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n    };\n\n    if (mode == 0 || main_lid == sub_lid) {\n        scan_list(main_lid, limit_ids);\n    } else if (mode == 2) {\n        scan_list(sub_lid, limit_ids);\n    } else {\n        int limA = (limit_ids * 2 + 2) / 3;\n        int limB = limit_ids - limA;\n        scan_list(main_lid, limA);\n        scan_list(sub_lid, limB);\n    }\n\n    if (top.empty()) {\n        for (int id = 1; id <= N; id++) {\n            if (selected[id]) continue;\n            Insertion ins = find_best_insertion(seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n    }\n\n    return top;\n}\n\nState construct_solution(\n    int pool_limit,\n    bool randomized,\n    int main_lid,\n    int sub_lid,\n    int mode,\n    XorShift64& rng,\n    const Timer& timer,\n    double end_time\n) {\n    State st;\n    st.seq = {0, 0};\n    st.selected.assign(N + 1, 0);\n    st.cost = 0;\n\n    int cnt = 0;\n    int topK = randomized ? 6 : 1;\n\n    while (cnt < 50) {\n        if (timer.elapsed() >= end_time) break;\n        auto top = collect_top_insertions_mode(st.seq, st.selected, main_lid, sub_lid, mode, pool_limit, topK, &timer, end_time);\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    while (cnt < 50) {\n        auto top = collect_top_insertions_mode(st.seq, st.selected, main_lid, sub_lid, mode, N, 1);\n        auto chosen = top[0];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.selected[chosen.id] = 1;\n        st.cost += chosen.delta;\n        cnt++;\n    }\n\n    return st;\n}\n\nState rebuild_route_for_selected(const vector<char>& selected, bool randomized, XorShift64& rng) {\n    vector<int> ids = get_selected_ids(selected);\n\n    State st;\n    st.seq = {0, 0};\n    st.selected = selected;\n    st.cost = 0;\n\n    vector<char> used(N + 1, 0);\n    int topK = randomized ? 7 : 1;\n\n    for (int step = 0; step < 50; step++) {\n        vector<Cand> top;\n        top.reserve(topK);\n        for (int id : ids) {\n            if (used[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(top, Cand{ins.delta, id, ins}, topK);\n        }\n        int idx = randomized ? pick_rcl_index((int)top.size(), rng) : 0;\n        auto chosen = top[idx];\n        st.seq = apply_insertion(st.seq, chosen.id, chosen.ins);\n        st.cost += chosen.delta;\n        used[chosen.id] = 1;\n    }\n    return st;\n}\n\nbool improve_adjacent_swap(State& st, const Timer& timer, double end_time, int max_passes = 20) {\n    bool any = false;\n    int m = (int)st.seq.size();\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_delta = 0;\n        int best_i = -1;\n\n        for (int i = 1; i + 2 < m; i++) {\n            if (timer.elapsed() >= end_time) break;\n            int a = st.seq[i];\n            int b = st.seq[i + 1];\n            if (a == 0 || b == 0) continue;\n            if (a <= N && b == N + a) continue;\n\n            int prev = st.seq[i - 1];\n            int next = st.seq[i + 2];\n\n            int delta = dist_node(prev, b) + dist_node(b, a) + dist_node(a, next)\n                      - dist_node(prev, a) - dist_node(a, b) - dist_node(b, next);\n\n            if (delta < best_delta) {\n                best_delta = delta;\n                best_i = i;\n            }\n        }\n\n        if (best_i == -1) break;\n        swap(st.seq[best_i], st.seq[best_i + 1]);\n        st.cost += best_delta;\n        any = true;\n    }\n\n    return any;\n}\n\nbool improve_event_relocate(State& st, const Timer& timer, double end_time, int max_passes = 50) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        vector<int> pos(TOT, -1);\n        for (int i = 0; i < (int)st.seq.size(); i++) pos[st.seq[i]] = i;\n\n        int best_new_cost = st.cost;\n        int best_node = -1;\n        int best_gap = -1;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            int u = pickup_node(id);\n            int v = delivery_node(id);\n            int pu = pos[u];\n            int pv = pos[v];\n\n            {\n                int prev = st.seq[pu - 1];\n                int next = st.seq[pu + 1];\n                int cost_removed = st.cost - (dist_node(prev, u) + dist_node(u, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, u);\n\n                int pdr = pv - 1;\n                auto ins = find_best_single_insertion(seq_removed, u, 0, pdr - 1);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = u;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n\n            {\n                int prev = st.seq[pv - 1];\n                int next = st.seq[pv + 1];\n                int cost_removed = st.cost - (dist_node(prev, v) + dist_node(v, next) - dist_node(prev, next));\n                vector<int> seq_removed = remove_node_once(st.seq, v);\n\n                int ppr = pu;\n                auto ins = find_best_single_insertion(seq_removed, v, ppr, (int)seq_removed.size() - 2);\n                if (ins.g != -1) {\n                    int new_cost = cost_removed + ins.delta;\n                    if (new_cost < best_new_cost) {\n                        best_new_cost = new_cost;\n                        best_node = v;\n                        best_gap = ins.g;\n                    }\n                }\n            }\n        }\n\n        if (best_node == -1) break;\n        vector<int> seq_removed = remove_node_once(st.seq, best_node);\n        st.seq = insert_single_node(seq_removed, best_node, best_gap);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\nbool improve_pair_relocate(State& st, const Timer& timer, double end_time, int max_passes = 100) {\n    bool any = false;\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_new_cost = st.cost;\n        int best_id = -1;\n        Insertion best_ins;\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            if (timer.elapsed() >= end_time) break;\n\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int cost_removed = route_cost(seq_removed);\n            Insertion ins = find_best_insertion(seq_removed, id);\n            int new_cost = cost_removed + ins.delta;\n\n            if (new_cost < best_new_cost) {\n                best_new_cost = new_cost;\n                best_id = id;\n                best_ins = ins;\n            }\n        }\n\n        if (best_id == -1) break;\n        vector<int> seq_removed = remove_order(st.seq, best_id);\n        st.seq = apply_insertion(seq_removed, best_id, best_ins);\n        st.cost = best_new_cost;\n        any = true;\n    }\n\n    return any;\n}\n\n// reversing [l, r] is valid iff no order has both endpoints inside [l, r]\nbool improve_two_opt(State& st, const Timer& timer, double end_time, int max_passes = 20) {\n    bool any = false;\n    int m = (int)st.seq.size();\n\n    for (int pass = 0; pass < max_passes; pass++) {\n        if (timer.elapsed() >= end_time) break;\n\n        int best_delta = 0;\n        int best_l = -1, best_r = -1;\n        vector<int> cnt(N + 1, 0);\n\n        for (int l = 1; l <= m - 3; l++) {\n            if (timer.elapsed() >= end_time) break;\n            fill(cnt.begin(), cnt.end(), 0);\n\n            for (int r = l; r <= m - 2; r++) {\n                int node = st.seq[r];\n                if (node == 0) break;\n                int id = (node <= N ? node : node - N);\n                cnt[id]++;\n                if (cnt[id] == 2) break;\n\n                int delta =\n                    dist_node(st.seq[l - 1], st.seq[r]) +\n                    dist_node(st.seq[l], st.seq[r + 1]) -\n                    dist_node(st.seq[l - 1], st.seq[l]) -\n                    dist_node(st.seq[r], st.seq[r + 1]);\n\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_l = l;\n                    best_r = r;\n                }\n            }\n        }\n\n        if (best_l == -1) break;\n        reverse(st.seq.begin() + best_l, st.seq.begin() + best_r + 1);\n        st.cost += best_delta;\n        any = true;\n    }\n\n    return any;\n}\n\nvoid optimize_route(State& st, const Timer& timer, double end_time) {\n    while (timer.elapsed() < end_time) {\n        int old_cost = st.cost;\n\n        double t0 = min(end_time, timer.elapsed() + 0.018);\n        improve_two_opt(st, timer, t0, 3);\n\n        double t1 = min(end_time, timer.elapsed() + 0.010);\n        improve_adjacent_swap(st, timer, t1, 4);\n\n        double t2 = min(end_time, timer.elapsed() + 0.018);\n        improve_event_relocate(st, timer, t2, 3);\n\n        double t3 = min(end_time, timer.elapsed() + 0.018);\n        improve_pair_relocate(st, timer, t3, 2);\n\n        if (st.cost >= old_cost) break;\n    }\n}\n\nvoid improve_swap(State& st, const Timer& timer, double end_time) {\n    const int TOP_REMOVE = 12;\n    const int TOP_ADD = 120;\n\n    while (timer.elapsed() < end_time) {\n        struct RemCand {\n            int gain;\n            int id;\n        };\n        vector<RemCand> rems;\n        rems.reserve(50);\n\n        for (int id = 1; id <= N; id++) {\n            if (!st.selected[id]) continue;\n            vector<int> seq_removed = remove_order(st.seq, id);\n            int removed_cost = route_cost(seq_removed);\n            int gain = st.cost - removed_cost;\n            rems.push_back({gain, id});\n        }\n\n        sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.id < b.id;\n        });\n        if ((int)rems.size() > TOP_REMOVE) rems.resize(TOP_REMOVE);\n\n        vector<Cand> adds;\n        adds.reserve(TOP_ADD);\n        for (int id = 1; id <= N; id++) {\n            if (timer.elapsed() >= end_time) break;\n            if (st.selected[id]) continue;\n            Insertion ins = find_best_insertion(st.seq, id);\n            push_top_k(adds, Cand{ins.delta, id, ins}, TOP_ADD);\n        }\n\n        int best_new_cost = st.cost;\n        int best_remove = -1, best_add = -1;\n        Insertion best_ins;\n\n        for (const auto& rc : rems) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> seq_removed = remove_order(st.seq, rc.id);\n            int cost_removed = route_cost(seq_removed);\n\n            for (const auto& ac : adds) {\n                Insertion ins = find_best_insertion(seq_removed, ac.id);\n                int new_cost = cost_removed + ins.delta;\n                if (new_cost < best_new_cost) {\n                    best_new_cost = new_cost;\n                    best_remove = rc.id;\n                    best_add = ac.id;\n                    best_ins = ins;\n                }\n            }\n        }\n\n        if (best_remove == -1) break;\n\n        st.selected[best_remove] = 0;\n        st.selected[best_add] = 1;\n        vector<int> seq_removed = remove_order(st.seq, best_remove);\n        st.seq = apply_insertion(seq_removed, best_add, best_ins);\n        st.cost = best_new_cost;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(st, timer, sub_end);\n    }\n}\n\nbool destroy_and_repair_once(State& st, const Timer& timer, double end_time, XorShift64& rng) {\n    if (timer.elapsed() >= end_time) return false;\n\n    auto selected_ids = get_selected_ids(st.selected);\n\n    struct RemCand {\n        int gain;\n        int id;\n    };\n    vector<RemCand> rems;\n    rems.reserve(50);\n    for (int id : selected_ids) {\n        vector<int> seq_removed = remove_order(st.seq, id);\n        int removed_cost = route_cost(seq_removed);\n        int gain = st.cost - removed_cost;\n        rems.push_back({gain, id});\n    }\n    sort(rems.begin(), rems.end(), [](const RemCand& a, const RemCand& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        return a.id < b.id;\n    });\n\n    int elite_rem = min(12, (int)rems.size());\n\n    for (int trial = 0; trial < 12 && timer.elapsed() < end_time; trial++) {\n        int k = (rng.next_int(0, 99) < 70 ? 2 : 3);\n\n        vector<int> remset;\n        remset.reserve(k);\n        while ((int)remset.size() < k) {\n            int id;\n            if (rng.next_int(0, 99) < 80) {\n                id = rems[rng.next_int(0, elite_rem - 1)].id;\n            } else {\n                id = selected_ids[rng.next_int(0, (int)selected_ids.size() - 1)];\n            }\n            bool dup = false;\n            for (int x : remset) if (x == id) dup = true;\n            if (!dup) remset.push_back(id);\n        }\n\n        State tmp;\n        tmp.selected = st.selected;\n        for (int id : remset) tmp.selected[id] = 0;\n        tmp.seq = remove_orders(st.seq, remset);\n        tmp.cost = route_cost(tmp.seq);\n\n        for (int rep = 0; rep < k; rep++) {\n            if (timer.elapsed() >= end_time) break;\n            int alt = rng.next_int(0, NLIST - 1);\n            auto top = collect_top_insertions_mode(tmp.seq, tmp.selected, 0, alt, 1, 800, 6, &timer, end_time);\n            int idx = pick_rcl_index((int)top.size(), rng);\n            auto chosen = top[idx];\n            tmp.seq = apply_insertion(tmp.seq, chosen.id, chosen.ins);\n            tmp.selected[chosen.id] = 1;\n            tmp.cost += chosen.delta;\n        }\n\n        if ((int)get_selected_ids(tmp.selected).size() != 50) continue;\n\n        double sub_end = min(end_time, timer.elapsed() + 0.05);\n        optimize_route(tmp, timer, sub_end);\n\n        if (tmp.cost < st.cost) {\n            st = move(tmp);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    X[0] = 400;\n    Y[0] = 400;\n\n    long long seed = 123456789;\n\n    for (int i = 1; i <= N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        X[i] = a;\n        Y[i] = b;\n        X[N + i] = c;\n        Y[N + i] = d;\n\n        int d0p = abs(400 - a) + abs(400 - b);\n        int dpd = abs(a - c) + abs(b - d);\n        int dd0 = abs(c - 400) + abs(d - 400);\n\n        d0p_[i] = d0p;\n        dpd_[i] = dpd;\n        dd0_[i] = dd0;\n\n        int center_sum = d0p + dd0;\n        baseScore[i] = 3 * (d0p + dpd + dd0) + center_sum;\n\n        seed = seed * 1000003 + a * 911 + b * 3571 + c * 1021 + d;\n    }\n\n    DM.assign(TOT * TOT, 0);\n    for (int i = 0; i < TOT; i++) {\n        for (int j = 0; j < TOT; j++) {\n            DM[i * TOT + j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n        }\n    }\n\n    order_lists.assign(NLIST, vector<int>(N));\n    for (int t = 0; t < NLIST; t++) {\n        iota(order_lists[t].begin(), order_lists[t].end(), 1);\n    }\n\n    auto mid_score = [&](int id) {\n        return abs((X[id] + X[N + id]) - 800) + abs((Y[id] + Y[N + id]) - 800);\n    };\n\n    sort(order_lists[0].begin(), order_lists[0].end(), [&](int i, int j) {\n        int si = baseScore[i], sj = baseScore[j];\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    sort(order_lists[1].begin(), order_lists[1].end(), [&](int i, int j) {\n        int si = d0p_[i] + dpd_[i] + dd0_[i];\n        int sj = d0p_[j] + dpd_[j] + dd0_[j];\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    sort(order_lists[2].begin(), order_lists[2].end(), [&](int i, int j) {\n        int si = d0p_[i] + dd0_[i];\n        int sj = d0p_[j] + dd0_[j];\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    sort(order_lists[3].begin(), order_lists[3].end(), [&](int i, int j) {\n        int si = mid_score(i) * 2 + dpd_[i];\n        int sj = mid_score(j) * 2 + dpd_[j];\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    sort(order_lists[4].begin(), order_lists[4].end(), [&](int i, int j) {\n        int si = max(d0p_[i], dd0_[i]) * 2 + dpd_[i];\n        int sj = max(d0p_[j], dd0_[j]) * 2 + dpd_[j];\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    Timer timer;\n    XorShift64 rng((uint64_t)seed);\n\n    State best;\n    bool has_best = false;\n\n    vector<int> pool_limits = {120, 180, 260, 360, 500, 700, 1000};\n\n    // 3 modes:\n    // 0 = pure base\n    // 1 = anchored mix (base + alt)\n    // 2 = pure alt\n    int attempt = 0;\n    while (timer.elapsed() < 0.60) {\n        int mode = attempt % 3;\n        int alt = (attempt / 3) % NLIST;\n        int pool = pool_limits[(attempt / (3 * NLIST)) % (int)pool_limits.size()];\n        bool randomized = (attempt > 0);\n\n        int main_lid = 0;\n        int sub_lid = alt;\n        if (mode == 0) {\n            main_lid = 0;\n            sub_lid = 0;\n        } else if (mode == 1) {\n            main_lid = 0;\n            sub_lid = alt;\n        } else {\n            main_lid = alt;\n            sub_lid = alt;\n        }\n\n        State st = construct_solution(pool, randomized, main_lid, sub_lid, mode, rng, timer, 0.64);\n\n        double sub_end = min(0.84, TL);\n        optimize_route(st, timer, sub_end);\n\n        if (!has_best || st.cost < best.cost) {\n            best = move(st);\n            has_best = true;\n        }\n        attempt++;\n    }\n\n    if (!has_best) {\n        best = construct_solution(1000, false, 0, 0, 0, rng, timer, TL);\n    }\n\n    optimize_route(best, timer, 1.05);\n    improve_swap(best, timer, 1.30);\n    optimize_route(best, timer, 1.50);\n\n    int fail_dr = 0;\n    while (timer.elapsed() < 1.74 && fail_dr < 4) {\n        if (destroy_and_repair_once(best, timer, 1.79, rng)) {\n            fail_dr = 0;\n            double sub_end = min(1.81, TL);\n            optimize_route(best, timer, sub_end);\n        } else {\n            fail_dr++;\n        }\n    }\n\n    int rebuild_trials = 0;\n    while (timer.elapsed() < 1.84) {\n        bool randomized = (rebuild_trials % 3 != 0);\n        State cand = rebuild_route_for_selected(best.selected, randomized, rng);\n        double sub_end = min(1.875, TL);\n        optimize_route(cand, timer, sub_end);\n        if (cand.cost < best.cost) best = move(cand);\n        rebuild_trials++;\n    }\n\n    improve_swap(best, timer, 1.89);\n    optimize_route(best, timer, TL - 0.01);\n\n    auto ids = get_selected_ids(best.selected);\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.seq.size();\n    for (int node : best.seq) {\n        cout << ' ' << X[node] << ' ' << Y[node];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int S = 64;   // even\nstatic constexpr int H = S / 2;\nstatic constexpr int INF = 1e9;\n\nstruct Edge {\n    int u, v, d;\n};\n\ntemplate <int MAXN>\nstruct UnionFind {\n    int p[MAXN], sz[MAXN];\n\n    inline void init(int n) {\n        for (int i = 0; i < n; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\n\n    inline int leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline int leader_const(int x) const {\n        while (p[x] != x) x = p[x];\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    inline bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 0x123456789abcdefULL) : 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(uint32_t mod) {\n        return (uint32_t)(next_u64() % mod);\n    }\n};\n\nstatic Edge edges[M];\nstatic int weights[S][M];\nstatic int orders[S][M];\nstatic int order_d[M];\n\n// Pure topological check on the remaining graph after contracting accepted components.\nstatic inline bool can_connect_future(\n    int next_idx,\n    int K,\n    const int cid[N]\n) {\n    if (K == 1) return true;\n\n    UnionFind<N> uf;\n    uf.init(K);\n    int need = K - 1;\n\n    for (int idx = next_idx; idx < M; ++idx) {\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n        if (uf.merge(a, b)) {\n            if (--need == 0) return true;\n        }\n    }\n    return false;\n}\n\n// Sampled world threshold: weight at which cu and cv first become connected in Kruskal.\nstatic inline int estimate_threshold_sample(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int cu,\n    int cv,\n    const int* order,\n    const int* weight\n) {\n    UnionFind<N> uf;\n    uf.init(K);\n\n    for (int t = 0; t < M; ++t) {\n        int idx = order[t];\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (uf.merge(a, b) && uf.same(cu, cv)) {\n            return weight[idx];\n        }\n    }\n    return INF;\n}\n\n// Deterministic baseline threshold using d-order.\n// Since mean edge length is 2*d, the baseline threshold is 2 * (threshold in d-order).\nstatic inline int estimate_threshold_d(\n    int next_idx,\n    int K,\n    const int cid[N],\n    int cu,\n    int cv\n) {\n    UnionFind<N> uf;\n    uf.init(K);\n\n    for (int t = 0; t < M; ++t) {\n        int idx = order_d[t];\n        if (idx < next_idx) continue;\n\n        int a = cid[edges[idx].u];\n        int b = cid[edges[idx].v];\n        if (a == b) continue;\n\n        if (uf.merge(a, b) && uf.same(cu, cv)) {\n            return edges[idx].d;\n        }\n    }\n    return INF;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int xs[N], ys[N];\n    for (int i = 0; i < N; ++i) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = xs[u] - xs[v];\n        long long dy = ys[u] - ys[v];\n        int d = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Deterministic baseline order by d.\n    for (int i = 0; i < M; ++i) order_d[i] = i;\n    sort(order_d, order_d + M, [&](int a, int b) {\n        if (edges[a].d != edges[b].d) return edges[a].d < edges[b].d;\n        return a < b;\n    });\n\n    // Stratified antithetic sampling.\n    SplitMix64 rng(0x3141592653589793ULL);\n    vector<int> perm(H);\n\n    for (int i = 0; i < M; ++i) {\n        iota(perm.begin(), perm.end(), 0);\n        for (int j = H - 1; j >= 1; --j) {\n            int k = (int)rng.next_u32(j + 1);\n            swap(perm[j], perm[k]);\n        }\n\n        int d = edges[i].d;\n        int range = 2 * d + 1; // t in [0, 2d]\n\n        for (int k = 0; k < H; ++k) {\n            int q = perm[k];\n            int L = (long long)range * q / H;\n            int R = (long long)range * (q + 1) / H - 1;\n            if (R < L) R = L;\n            int t = (L + R) >> 1;\n\n            weights[2 * k][i] = d + t;\n            weights[2 * k + 1][i] = 3 * d - t;\n        }\n    }\n\n    for (int s = 0; s < S; ++s) {\n        for (int i = 0; i < M; ++i) orders[s][i] = i;\n        sort(orders[s], orders[s] + M, [&](int a, int b) {\n            if (weights[s][a] != weights[s][b]) return weights[s][a] < weights[s][b];\n            return a < b;\n        });\n    }\n\n    UnionFind<N> accepted;\n    accepted.init(N);\n\n    int cid[N];\n    int K = N;\n    bool comp_dirty = true;\n\n    auto rebuild_components = [&]() {\n        int mp[N];\n        for (int i = 0; i < N; ++i) mp[i] = -1;\n        K = 0;\n        for (int v = 0; v < N; ++v) {\n            int r = accepted.leader_const(v);\n            if (mp[r] == -1) mp[r] = K++;\n            cid[v] = mp[r];\n        }\n        comp_dirty = false;\n    };\n\n    for (int i = 0; i < M; ++i) {\n        int l;\n        cin >> l;\n\n        int u = edges[i].u;\n        int v = edges[i].v;\n        int ans = 0;\n\n        if (!accepted.same(u, v)) {\n            if (comp_dirty) rebuild_components();\n\n            int cu = cid[u];\n            int cv = cid[v];\n\n            if (!can_connect_future(i + 1, K, cid)) {\n                ans = 1;\n            } else {\n                long long sum_thr = 0;\n                for (int s = 0; s < S; ++s) {\n                    int thr = estimate_threshold_sample(i + 1, K, cid, cu, cv, orders[s], weights[s]);\n                    sum_thr += thr;\n                }\n                double sample_mean = (double)sum_thr / S;\n\n                int d_thr = estimate_threshold_d(i + 1, K, cid, cu, cv);\n                double baseline = 2.0 * d_thr;\n\n                // Mild shrinkage toward the deterministic baseline.\n                // More baseline weight when many components remain.\n                double rem_comp = (double)(K - 1) / (N - 1); // 1 early, 0 late\n                double alpha = 0.90 - 0.08 * rem_comp;       // ~0.82 early, ~0.90 late\n\n                double blended = alpha * sample_mean + (1.0 - alpha) * baseline;\n\n                if ((double)l <= blended) ans = 1;\n            }\n        }\n\n        if (ans) {\n            accepted.merge(u, v);\n            comp_dirty = true;\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n    bool operator==(const Pos& o) const { return x == o.x && y == o.y; }\n    bool operator!=(const Pos& o) const { return !(*this == o); }\n};\n\nstatic constexpr int B = 30;\nstatic constexpr int T = 300;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nvector<Pos> pets, humans;\nvector<int> petType;\nbool wallg[31][31];\n\n// outer room parameters in normalized (top-left) coordinates\nint chosenCorner = 0;\nint outerH = 8, outerW = 8;\n// keepDoorOuter = 0 : keep bottom door (outerH+1, outerW)\n// keepDoorOuter = 1 : keep right  door (outerH, outerW+1)\nint keepDoorOuter = 0;\n\n// current final human room after optional inner split\nint curH = 8, curW = 8;\n\n// parking targets for current human objective region\nvector<Pos> parkTarget;\n\n// optional inner split (used once after outer closure)\n// splitType = 0 none, 1 horizontal keep top, 2 vertical keep left\nbool didInnerSplit = false;\nbool innerActive = false;\nint splitType = 0;\nint splitPos = 0; // wall row or col\n\nbool inside(int x, int y) {\n    return 1 <= x && x <= B && 1 <= y && y <= B;\n}\n\nPos addDir(Pos p, char d) {\n    if (d == 'U' || d == 'u') --p.x;\n    else if (d == 'D' || d == 'd') ++p.x;\n    else if (d == 'L' || d == 'l') --p.y;\n    else if (d == 'R' || d == 'r') ++p.y;\n    return p;\n}\n\nPos transformPos(Pos p, int corner) {\n    if (corner == 0) return p;\n    if (corner == 1) return {p.x, B + 1 - p.y};\n    if (corner == 2) return {B + 1 - p.x, p.y};\n    return {B + 1 - p.x, B + 1 - p.y};\n}\n\nchar mapDirByCorner(char c, int corner) {\n    bool low = ('a' <= c && c <= 'z');\n    char d = (char)toupper(c);\n    if (corner == 1 || corner == 3) {\n        if (d == 'L') d = 'R';\n        else if (d == 'R') d = 'L';\n    }\n    if (corner == 2 || corner == 3) {\n        if (d == 'U') d = 'D';\n        else if (d == 'D') d = 'U';\n    }\n    if (low) d = (char)tolower(d);\n    return d;\n}\n\nint manhattan(Pos a, Pos b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<Pos> transformedVec(const vector<Pos>& src, int corner) {\n    vector<Pos> res = src;\n    for (auto& p : res) p = transformPos(p, corner);\n    return res;\n}\n\nbool canBuildCell(int tx, int ty, const vector<Pos>& hs, const vector<Pos>& ps) {\n    if (!inside(tx, ty)) return false;\n    if (wallg[tx][ty]) return false;\n    for (auto& h : hs) {\n        if (h.x == tx && h.y == ty) return false;\n    }\n    for (auto& p : ps) {\n        if (p.x == tx && p.y == ty) return false;\n        if (abs(p.x - tx) + abs(p.y - ty) == 1) return false;\n    }\n    return true;\n}\n\nchar bfsNextStep(Pos s, Pos t) {\n    if (s == t) return '.';\n    if (!inside(t.x, t.y) || wallg[t.x][t.y]) return '.';\n\n    static int dist[31][31];\n    for (int i = 1; i <= B; ++i) {\n        for (int j = 1; j <= B; ++j) dist[i][j] = -1;\n    }\n\n    queue<Pos> q;\n    q.push(t);\n    dist[t.x][t.y] = 0;\n\n    const char dirs[4] = {'U', 'D', 'L', 'R'};\n    while (!q.empty()) {\n        Pos cur = q.front(); q.pop();\n        for (char d : dirs) {\n            Pos nx = addDir(cur, d);\n            if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n            if (dist[nx.x][nx.y] != -1) continue;\n            dist[nx.x][nx.y] = dist[cur.x][cur.y] + 1;\n            q.push(nx);\n        }\n    }\n\n    int best = INF;\n    char ans = '.';\n    const char order[4] = {'U', 'L', 'R', 'D'};\n    for (char d : order) {\n        Pos nx = addDir(s, d);\n        if (!inside(nx.x, nx.y) || wallg[nx.x][nx.y]) continue;\n        if (dist[nx.x][nx.y] == -1) continue;\n        if (dist[nx.x][nx.y] < best) {\n            best = dist[nx.x][nx.y];\n            ans = d;\n        }\n    }\n    return ans;\n}\n\nbool allHumansInsideRect(const vector<Pos>& hs, int H, int W) {\n    for (auto& h : hs) {\n        if (h.x > H || h.y > W) return false;\n    }\n    return true;\n}\n\nint countPetsInsideRect(const vector<Pos>& ps, int H, int W) {\n    int c = 0;\n    for (auto& p : ps) if (p.x <= H && p.y <= W) ++c;\n    return c;\n}\n\nvoid computeParkTargets(int H, int W, const vector<Pos>& hs) {\n    vector<Pos> spots;\n    for (int sum = 2; sum <= H + W; ++sum) {\n        for (int x = 1; x <= H; ++x) {\n            int y = sum - x;\n            if (1 <= y && y <= W) {\n                if (x == H && y == W) continue;\n                spots.push_back({x, y});\n            }\n        }\n    }\n    if (spots.empty()) spots.push_back({1, 1});\n\n    parkTarget.assign(M, {1, 1});\n    vector<int> used(spots.size(), 0);\n    for (int i = 0; i < M; ++i) {\n        int best = -1, bestd = INF;\n        for (int k = 0; k < (int)spots.size(); ++k) if (!used[k]) {\n            int d = manhattan(hs[i], spots[k]);\n            if (d < bestd) {\n                bestd = d;\n                best = k;\n            }\n        }\n        if (best == -1) best = 0;\n        used[best] = 1;\n        parkTarget[i] = spots[best];\n    }\n}\n\nstruct Task {\n    Pos pos;   // human must stand here\n    Pos wall;  // then build this wall cell\n    char act;  // lowercase action\n};\n\n// ---------- outer enclosure helpers ----------\n\nPos outerDoorCell() {\n    if (keepDoorOuter == 0) return {outerH + 1, outerW};\n    return {outerH, outerW + 1};\n}\n\nchar outerDoorAct() {\n    return (keepDoorOuter == 0 ? 'd' : 'r');\n}\n\nbool allOuterWallsExceptDoorBuilt() {\n    if (keepDoorOuter == 0) {\n        for (int y = 1; y <= outerW - 1; ++y) if (!wallg[outerH + 1][y]) return false;\n        for (int x = 1; x <= outerH; ++x) if (!wallg[x][outerW + 1]) return false;\n    } else {\n        for (int y = 1; y <= outerW; ++y) if (!wallg[outerH + 1][y]) return false;\n        for (int x = 1; x <= outerH - 1; ++x) if (!wallg[x][outerW + 1]) return false;\n    }\n    return true;\n}\n\nbool outerFullyClosed() {\n    Pos d = outerDoorCell();\n    return allOuterWallsExceptDoorBuilt() && wallg[d.x][d.y];\n}\n\nvector<Task> getOuterBuildTasks() {\n    vector<Task> tasks;\n    if (keepDoorOuter == 0) {\n        for (int y = 1; y <= outerW - 1; ++y) {\n            if (!wallg[outerH + 1][y]) tasks.push_back({{outerH, y}, {outerH + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= outerH; ++x) {\n            if (!wallg[x][outerW + 1]) tasks.push_back({{x, outerW}, {x, outerW + 1}, 'r'});\n        }\n    } else {\n        for (int y = 1; y <= outerW; ++y) {\n            if (!wallg[outerH + 1][y]) tasks.push_back({{outerH, y}, {outerH + 1, y}, 'd'});\n        }\n        for (int x = 1; x <= outerH - 1; ++x) {\n            if (!wallg[x][outerW + 1]) tasks.push_back({{x, outerW}, {x, outerW + 1}, 'r'});\n        }\n    }\n    return tasks;\n}\n\nPos outerCloserStand() {\n    if (keepDoorOuter == 0) return {outerH, outerW};\n    return {outerH, outerW};\n}\n\n// ---------- inner split helpers ----------\n\nint innerKeepH() {\n    if (splitType == 1) return splitPos - 1;\n    return curH;\n}\n\nint innerKeepW() {\n    if (splitType == 2) return splitPos - 1;\n    return curW;\n}\n\nPos innerDoorCell() {\n    if (splitType == 1) return {splitPos, curW};\n    return {curH, splitPos};\n}\n\nchar innerDoorAct() {\n    return (splitType == 1 ? 'd' : 'r');\n}\n\nPos innerCloserStand() {\n    if (splitType == 1) return {splitPos - 1, curW};\n    return {curH, splitPos - 1};\n}\n\nbool allInnerWallsExceptDoorBuilt() {\n    if (!innerActive) return true;\n    if (splitType == 1) {\n        for (int y = 1; y <= curW - 1; ++y) if (!wallg[splitPos][y]) return false;\n    } else {\n        for (int x = 1; x <= curH - 1; ++x) if (!wallg[x][splitPos]) return false;\n    }\n    return true;\n}\n\nbool innerFullyClosedNow() {\n    if (!innerActive) return false;\n    Pos d = innerDoorCell();\n    return allInnerWallsExceptDoorBuilt() && wallg[d.x][d.y];\n}\n\nbool allHumansInInnerSide(const vector<Pos>& hs) {\n    if (splitType == 1) {\n        for (auto& h : hs) if (h.x >= splitPos) return false;\n    } else {\n        for (auto& h : hs) if (h.y >= splitPos) return false;\n    }\n    return true;\n}\n\nint countPetsInInnerSide(const vector<Pos>& ps) {\n    int c = 0;\n    if (splitType == 1) {\n        for (auto& p : ps) if (p.x < splitPos && p.y <= curW) ++c;\n    } else {\n        for (auto& p : ps) if (p.y < splitPos && p.x <= curH) ++c;\n    }\n    return c;\n}\n\nvector<Task> getInnerBuildTasks() {\n    vector<Task> tasks;\n    if (splitType == 1) {\n        // horizontal line at row splitPos, keep top, leave door at y=curW\n        for (int y = 1; y <= curW - 1; ++y) {\n            if (!wallg[splitPos][y]) tasks.push_back({{splitPos - 1, y}, {splitPos, y}, 'd'});\n        }\n    } else {\n        // vertical line at col splitPos, keep left, leave door at x=curH\n        for (int x = 1; x <= curH - 1; ++x) {\n            if (!wallg[x][splitPos]) tasks.push_back({{x, splitPos - 1}, {x, splitPos}, 'r'});\n        }\n    }\n    return tasks;\n}\n\ndouble boundaryPressureOuter(const vector<Pos>& ps, int H, int W, int keepDoor) {\n    double s = 0.0;\n    for (auto& p : ps) {\n        // pressure near bottom wall\n        if (abs(p.x - (H + 1)) <= 1 && 1 <= p.y && p.y <= W) s += 2.0;\n        // pressure near right wall\n        if (abs(p.y - (W + 1)) <= 1 && 1 <= p.x && p.x <= H) s += 2.0;\n        // extra near door\n        Pos d = (keepDoor == 0 ? Pos{H + 1, W} : Pos{H, W + 1});\n        int md = manhattan(p, d);\n        if (md <= 8) s += (9 - md) * 0.7;\n    }\n    return s;\n}\n\nvoid chooseStrategy(const vector<Pos>& initPetsActual, const vector<Pos>& initHumansActual) {\n    double bestValue = -1e100;\n    int bestCorner = 0, bestH = 8, bestW = 8, bestKeep = 0;\n\n    for (int corner = 0; corner < 4; ++corner) {\n        auto tp = transformedVec(initPetsActual, corner);\n        auto th = transformedVec(initHumansActual, corner);\n\n        int occ[31][31] = {};\n        for (auto& p : tp) occ[p.x][p.y]++;\n\n        int pref[31][31] = {};\n        for (int i = 1; i <= B; ++i) {\n            for (int j = 1; j <= B; ++j) {\n                pref[i][j] = occ[i][j] + pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1];\n            }\n        }\n\n        for (int H = 4; H <= 18; ++H) {\n            for (int W = 4; W <= 18; ++W) {\n                int petCnt = pref[H][W];\n\n                int enterSum = 0, enterMax = 0;\n                for (auto& h : th) {\n                    int d = max(0, h.x - H) + max(0, h.y - W);\n                    enterSum += d;\n                    enterMax = max(enterMax, d);\n                }\n\n                for (int kd = 0; kd < 2; ++kd) {\n                    double press = boundaryPressureOuter(tp, H, W, kd);\n                    int buildCells = H + W - 1;\n                    double value =\n                        1.0 * H * W * pow(0.46, petCnt)\n                        - 0.46 * enterSum\n                        - 0.18 * enterMax\n                        - 0.18 * buildCells\n                        - 0.55 * press;\n\n                    if (petCnt == 0) value += 18.0;\n                    else if (petCnt == 1) value += 4.0;\n                    else value -= 2.0 * (petCnt - 1);\n\n                    if (value > bestValue) {\n                        bestValue = value;\n                        bestCorner = corner;\n                        bestH = H;\n                        bestW = W;\n                        bestKeep = kd;\n                    }\n                }\n            }\n        }\n    }\n\n    chosenCorner = bestCorner;\n    outerH = bestH;\n    outerW = bestW;\n    keepDoorOuter = bestKeep;\n    curH = outerH;\n    curW = outerW;\n\n    pets = transformedVec(initPetsActual, chosenCorner);\n    humans = transformedVec(initHumansActual, chosenCorner);\n\n    memset(wallg, 0, sizeof(wallg));\n    computeParkTargets(curH, curW, humans);\n}\n\n// returns true if activated\nbool tryActivateInnerSplit(const vector<Pos>& hs, const vector<Pos>& ps, int turn) {\n    if (didInnerSplit) return false;\n    if (!outerFullyClosed()) return false;\n    if (turn >= 265) return false;\n\n    int petsIn = countPetsInsideRect(ps, curH, curW);\n    if (petsIn == 0) return false;\n\n    double baseline = 1.0 * curH * curW * pow(0.5, petsIn);\n    double bestScore = baseline;\n    int bestType = 0, bestPos = 0;\n\n    // horizontal split: keep top\n    for (int x = 2; x <= curH; ++x) {\n        int keepH = x - 1;\n        int keepW = curW;\n        int petKeep = 0, linePress = 0, humanMove = 0;\n        for (auto& p : ps) {\n            if (p.x < x && p.y <= curW) ++petKeep;\n            if (abs(p.x - x) <= 1 && p.y <= curW) ++linePress;\n        }\n        for (auto& h : hs) {\n            if (h.x >= x && h.y <= curW) humanMove += (h.x - (x - 1));\n        }\n        if (petKeep >= petsIn) continue;\n        double score =\n            1.0 * keepH * keepW * pow(0.52, petKeep)\n            - 0.35 * curW\n            - 0.40 * humanMove\n            - 1.3 * linePress;\n        if (petKeep == 0) score += 6.0;\n        if (score > bestScore + 3.0) {\n            bestScore = score;\n            bestType = 1;\n            bestPos = x;\n        }\n    }\n\n    // vertical split: keep left\n    for (int y = 2; y <= curW; ++y) {\n        int keepH = curH;\n        int keepW = y - 1;\n        int petKeep = 0, linePress = 0, humanMove = 0;\n        for (auto& p : ps) {\n            if (p.y < y && p.x <= curH) ++petKeep;\n            if (abs(p.y - y) <= 1 && p.x <= curH) ++linePress;\n        }\n        for (auto& h : hs) {\n            if (h.y >= y && h.x <= curH) humanMove += (h.y - (y - 1));\n        }\n        if (petKeep >= petsIn) continue;\n        double score =\n            1.0 * keepH * keepW * pow(0.52, petKeep)\n            - 0.35 * curH\n            - 0.40 * humanMove\n            - 1.3 * linePress;\n        if (petKeep == 0) score += 6.0;\n        if (score > bestScore + 3.0) {\n            bestScore = score;\n            bestType = 2;\n            bestPos = y;\n        }\n    }\n\n    if (bestType == 0) return false;\n\n    didInnerSplit = true;\n    innerActive = true;\n    splitType = bestType;\n    splitPos = bestPos;\n    computeParkTargets(innerKeepH(), innerKeepW(), hs);\n    return true;\n}\n\nbool shouldCloseOuterDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 180 && petsInside <= 1) return true;\n    if (turn >= 230 && petsInside <= 2) return true;\n    if (turn >= 290 && petsInside <= 3) return true;\n    if (turn >= 297) return true;\n    return false;\n}\n\nbool shouldCloseInnerDoor(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 250 && petsInside <= 1) return true;\n    if (turn >= 290 && petsInside <= 2) return true;\n    if (turn >= 297) return true;\n    return false;\n}\n\nint nearestHumanTo(Pos target, const vector<Pos>& hs) {\n    int id = 0, bd = INF;\n    for (int i = 0; i < (int)hs.size(); ++i) {\n        int d = manhattan(hs[i], target);\n        if (d < bd) {\n            bd = d;\n            id = i;\n        }\n    }\n    return id;\n}\n\nvoid assignBuildActions(const vector<Pos>& hs0, const vector<Pos>& ps0,\n                        const vector<Task>& tasks, Pos closerStand, int reserveCloser,\n                        vector<char>& act) {\n    vector<int> assignedTask(M, -1);\n    vector<int> usedTask(tasks.size(), 0);\n    vector<int> usedHuman(M, 0);\n\n    if (reserveCloser != -1) {\n        usedHuman[reserveCloser] = 1;\n        act[reserveCloser] = bfsNextStep(hs0[reserveCloser], closerStand);\n    }\n\n    // immediate builds first\n    for (int i = 0; i < M; ++i) {\n        if (usedHuman[i]) continue;\n        for (int t = 0; t < (int)tasks.size(); ++t) {\n            if (usedTask[t]) continue;\n            if (hs0[i] == tasks[t].pos &&\n                canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) {\n                assignedTask[i] = t;\n                usedTask[t] = 1;\n                usedHuman[i] = 1;\n                break;\n            }\n        }\n    }\n\n    struct Cand {\n        int d, i, t;\n        bool operator<(const Cand& o) const {\n            if (d != o.d) return d < o.d;\n            if (i != o.i) return i < o.i;\n            return t < o.t;\n        }\n    };\n    vector<Cand> cand;\n    for (int i = 0; i < M; ++i) if (!usedHuman[i]) {\n        for (int t = 0; t < (int)tasks.size(); ++t) if (!usedTask[t]) {\n            int d = manhattan(hs0[i], tasks[t].pos);\n            if (hs0[i] == tasks[t].pos &&\n                !canBuildCell(tasks[t].wall.x, tasks[t].wall.y, hs0, ps0)) d += 3;\n            cand.push_back({d, i, t});\n        }\n    }\n    sort(cand.begin(), cand.end());\n    for (auto& c : cand) {\n        if (usedHuman[c.i] || usedTask[c.t]) continue;\n        usedHuman[c.i] = 1;\n        usedTask[c.t] = 1;\n        assignedTask[c.i] = c.t;\n    }\n\n    for (int i = 0; i < M; ++i) {\n        if (assignedTask[i] != -1) {\n            auto& task = tasks[assignedTask[i]];\n            if (hs0[i] == task.pos) {\n                if (canBuildCell(task.wall.x, task.wall.y, hs0, ps0)) act[i] = task.act;\n                else act[i] = '.';\n            } else {\n                act[i] = bfsNextStep(hs0[i], task.pos);\n            }\n        } else if (i != reserveCloser) {\n            act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<Pos> initPetsActual(N);\n    petType.resize(N);\n    for (int i = 0; i < N; ++i) {\n        cin >> initPetsActual[i].x >> initPetsActual[i].y >> petType[i];\n    }\n\n    cin >> M;\n    vector<Pos> initHumansActual(M);\n    for (int i = 0; i < M; ++i) cin >> initHumansActual[i].x >> initHumansActual[i].y;\n\n    chooseStrategy(initPetsActual, initHumansActual);\n\n    for (int turn = 0; turn < T; ++turn) {\n        vector<Pos> hs0 = humans;\n        vector<Pos> ps0 = pets;\n        vector<char> act(M, '.');\n\n        if (!outerFullyClosed()) {\n            if (!allOuterWallsExceptDoorBuilt()) {\n                vector<Task> tasks = getOuterBuildTasks();\n                int reserveCloser = -1;\n                if ((int)tasks.size() <= max(2, M / 3) || turn >= 220) {\n                    reserveCloser = nearestHumanTo(outerCloserStand(), hs0);\n                }\n                assignBuildActions(hs0, ps0, tasks, outerCloserStand(), reserveCloser, act);\n            } else {\n                Pos stand = outerCloserStand();\n                Pos door = outerDoorCell();\n                char doorAct = outerDoorAct();\n                int closer = nearestHumanTo(stand, hs0);\n\n                for (int i = 0; i < M; ++i) {\n                    if (i == closer) continue;\n                    act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                }\n\n                bool allIn = allHumansInsideRect(hs0, outerH, outerW);\n                int petsInside = countPetsInsideRect(ps0, outerH, outerW);\n                bool doClose = allIn && shouldCloseOuterDoor(turn, petsInside);\n\n                if (hs0[closer] != stand) {\n                    act[closer] = bfsNextStep(hs0[closer], stand);\n                } else {\n                    if (doClose && canBuildCell(door.x, door.y, hs0, ps0)) act[closer] = doorAct;\n                    else act[closer] = '.';\n                }\n            }\n        } else {\n            if (!innerActive) {\n                tryActivateInnerSplit(hs0, ps0, turn);\n            }\n\n            if (innerActive && !innerFullyClosedNow()) {\n                if (!allInnerWallsExceptDoorBuilt()) {\n                    vector<Task> tasks = getInnerBuildTasks();\n                    int reserveCloser = -1;\n                    if ((int)tasks.size() <= max(2, M / 3) || turn >= 275) {\n                        reserveCloser = nearestHumanTo(innerCloserStand(), hs0);\n                    }\n                    assignBuildActions(hs0, ps0, tasks, innerCloserStand(), reserveCloser, act);\n                } else {\n                    Pos stand = innerCloserStand();\n                    Pos door = innerDoorCell();\n                    char doorAct = innerDoorAct();\n                    int closer = nearestHumanTo(stand, hs0);\n\n                    for (int i = 0; i < M; ++i) {\n                        if (i == closer) continue;\n                        act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                    }\n\n                    bool allIn = allHumansInInnerSide(hs0);\n                    int petsInside = countPetsInInnerSide(ps0);\n                    bool doClose = allIn && shouldCloseInnerDoor(turn, petsInside);\n\n                    if (hs0[closer] != stand) {\n                        act[closer] = bfsNextStep(hs0[closer], stand);\n                    } else {\n                        if (doClose && canBuildCell(door.x, door.y, hs0, ps0)) act[closer] = doorAct;\n                        else act[closer] = '.';\n                    }\n                }\n            } else {\n                for (int i = 0; i < M; ++i) {\n                    act[i] = bfsNextStep(hs0[i], parkTarget[i]);\n                }\n            }\n        }\n\n        // sanitize build actions\n        set<pair<int,int>> buildSet;\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!canBuildCell(t.x, t.y, hs0, ps0)) {\n                    act[i] = '.';\n                    continue;\n                }\n                if (buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                    continue;\n                }\n                buildSet.insert({t.x, t.y});\n            }\n        }\n\n        // sanitize move actions\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (!inside(t.x, t.y) || wallg[t.x][t.y] || buildSet.count({t.x, t.y})) {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        string out(M, '.');\n        for (int i = 0; i < M; ++i) out[i] = mapDirByCorner(act[i], chosenCorner);\n        cout << out << '\\n';\n        cout.flush();\n\n        // update walls\n        for (int i = 0; i < M; ++i) {\n            if ('a' <= act[i] && act[i] <= 'z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (canBuildCell(t.x, t.y, hs0, ps0)) wallg[t.x][t.y] = true;\n            }\n        }\n\n        // update humans\n        for (int i = 0; i < M; ++i) {\n            if ('A' <= act[i] && act[i] <= 'Z') {\n                Pos t = addDir(hs0[i], act[i]);\n                if (inside(t.x, t.y) && !wallg[t.x][t.y] && !buildSet.count({t.x, t.y})) {\n                    humans[i] = t;\n                }\n            }\n        }\n\n        // if inner split just closed now, shrink current room\n        if (innerActive && innerFullyClosedNow()) {\n            curH = innerKeepH();\n            curW = innerKeepW();\n            innerActive = false;\n            computeParkTargets(curH, curW, humans);\n        }\n\n        // read pet moves\n        for (int i = 0; i < N; ++i) {\n            string s;\n            cin >> s;\n            for (char c : s) {\n                if (c == '.') continue;\n                char nc = mapDirByCorner(c, chosenCorner);\n                pets[i] = addDir(pets[i], nc);\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 = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr char DIRS[4] = {'U', 'D', 'L', 'R'};\n\nint si, sj, ti, tj;\ndouble P, Q;\nstring hwall[N];\nstring vwall[N - 1];\n\nint start_id, target_id;\nint nxtPos[V][4];\nint distToTarget[V];\n\ndouble adaptDP[MAXL + 2][V];\ndouble fwdDist[MAXL + 1][V];\n\ninline int id(int i, int j) { return i * N + j; }\ninline int r_of(int x) { return x / N; }\ninline int c_of(int x) { return x % N; }\n\ninline int dirIndex(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / (1ull << 53));\n    }\n} rng;\n\nstruct State {\n    array<float, V> pr{};\n    array<char, MAXL> path{};\n    double score = 0.0;\n    double upper = 0.0;\n    double pri = 0.0;\n    int len = 0;\n};\n\nstring toString(const State& st) {\n    return string(st.path.begin(), st.path.begin() + st.len);\n}\n\nvoid buildTransitions() {\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int x = id(i, j);\n\n            // U\n            if (i == 0 || vwall[i - 1][j] == '1') nxtPos[x][0] = x;\n            else nxtPos[x][0] = id(i - 1, j);\n\n            // D\n            if (i == N - 1 || vwall[i][j] == '1') nxtPos[x][1] = x;\n            else nxtPos[x][1] = id(i + 1, j);\n\n            // L\n            if (j == 0 || hwall[i][j - 1] == '1') nxtPos[x][2] = x;\n            else nxtPos[x][2] = id(i, j - 1);\n\n            // R\n            if (j == N - 1 || hwall[i][j] == '1') nxtPos[x][3] = x;\n            else nxtPos[x][3] = id(i, j + 1);\n        }\n    }\n}\n\nvoid bfsTargetDist() {\n    fill(distToTarget, distToTarget + V, (int)1e9);\n    queue<int> q;\n    distToTarget[target_id] = 0;\n    q.push(target_id);\n\n    while (!q.empty()) {\n        int x = q.front();\n        q.pop();\n        int d = distToTarget[x];\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n            if (distToTarget[y] > d + 1) {\n                distToTarget[y] = d + 1;\n                q.push(y);\n            }\n        }\n    }\n}\n\n// Relaxation: from each exact cell, future actions may be chosen adaptively.\n// This is an upper bound for the real open-loop problem.\nvoid buildAdaptiveDP() {\n    for (int x = 0; x < V; x++) adaptDP[MAXL + 1][x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        for (int x = 0; x < V; x++) {\n            if (x == target_id) {\n                adaptDP[step][x] = 0.0;\n                continue;\n            }\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int y = nxtPos[x][a];\n                double val = P * adaptDP[step + 1][x];\n                if (y == target_id) val += Q * reward;\n                else val += Q * adaptDP[step + 1][y];\n                if (val > best) best = val;\n            }\n            adaptDP[step][x] = best;\n        }\n    }\n}\n\nState initialState() {\n    State st;\n    st.pr.fill(0.0f);\n    st.pr[start_id] = 1.0f;\n    st.score = 0.0;\n    st.len = 0;\n    st.upper = adaptDP[1][start_id];\n    st.pri = st.upper + 5.0;\n    return st;\n}\n\nState extendState(const State& st, int a, int step) {\n    State nx;\n    nx.pr.fill(0.0f);\n    nx.path = st.path;\n    nx.path[st.len] = DIRS[a];\n    nx.len = st.len + 1;\n    nx.score = st.score;\n\n    double reward = 401.0 - step;\n\n    for (int x = 0; x < V; x++) {\n        float q = st.pr[x];\n        if (q < 1e-8f) continue;\n\n        int y = nxtPos[x][a];\n        if (y == target_id) {\n            float stay = q * (float)P;\n            if (stay > 0) nx.pr[x] += stay;\n            nx.score += (double)q * Q * reward;\n        } else if (y == x) {\n            nx.pr[x] += q;\n        } else {\n            float stay = q * (float)P;\n            float go = q * (float)Q;\n            if (stay > 0) nx.pr[x] += stay;\n            if (go > 0) nx.pr[y] += go;\n        }\n    }\n\n    double future = 0.0;\n    double sq = 0.0;\n    int nextStep = step + 1;\n    for (int x = 0; x < V; x++) {\n        double p = nx.pr[x];\n        if (p < 1e-12) continue;\n        future += p * adaptDP[nextStep][x];\n        sq += p * p;\n    }\n    nx.upper = nx.score + future;\n    nx.pri = nx.upper + 6.0 * sq;\n    return nx;\n}\n\nState applyPrefixState(const string& s) {\n    State st = initialState();\n    for (int step = 1; step <= (int)s.size(); step++) {\n        st = extendState(st, dirIndex(s[step - 1]), step);\n    }\n    return st;\n}\n\nState greedyComplete(State cur, bool usePri) {\n    for (int step = cur.len + 1; step <= MAXL; step++) {\n        State best;\n        bool first = true;\n        for (int a = 0; a < 4; a++) {\n            State nx = extendState(cur, a, step);\n            double key = usePri ? nx.pri : nx.upper;\n            if (first) {\n                best = std::move(nx);\n                first = false;\n            } else {\n                double bkey = usePri ? best.pri : best.upper;\n                if (key > bkey + 1e-12 ||\n                    (fabs(key - bkey) <= 1e-12 && nx.score > best.score)) {\n                    best = std::move(nx);\n                }\n            }\n        }\n        cur = std::move(best);\n    }\n    return cur;\n}\n\nstring completeByGreedy(const string& prefix, bool usePri) {\n    string pref = prefix;\n    if ((int)pref.size() > MAXL) pref.resize(MAXL);\n    State st = applyPrefixState(pref);\n    if (st.len == MAXL) return pref;\n    State full = greedyComplete(st, usePri);\n    return toString(full);\n}\n\ndouble evaluateString(const string& s) {\n    static double cur[V], nxt[V];\n    fill(cur, cur + V, 0.0);\n    cur[start_id] = 1.0;\n    double score = 0.0;\n\n    for (int step = 1; step <= (int)s.size(); step++) {\n        fill(nxt, nxt + V, 0.0);\n        int a = dirIndex(s[step - 1]);\n        double reward = 401.0 - step;\n\n        for (int x = 0; x < V; x++) {\n            double q = cur[x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                nxt[x] += q * P;\n                score += q * Q * reward;\n            } else if (y == x) {\n                nxt[x] += q;\n            } else {\n                nxt[x] += q * P;\n                nxt[y] += q * Q;\n            }\n        }\n        memcpy(cur, nxt, sizeof(double) * V);\n    }\n    return score;\n}\n\nvoid computeForwardDist(const string& s) {\n    for (int x = 0; x < V; x++) fwdDist[0][x] = 0.0;\n    fwdDist[0][start_id] = 1.0;\n\n    for (int step = 1; step <= MAXL; step++) {\n        int a = dirIndex(s[step - 1]);\n        for (int x = 0; x < V; x++) fwdDist[step][x] = 0.0;\n\n        for (int x = 0; x < V; x++) {\n            double q = fwdDist[step - 1][x];\n            if (q < 1e-14) continue;\n            int y = nxtPos[x][a];\n            if (y == target_id) {\n                fwdDist[step][x] += q * P;\n            } else if (y == x) {\n                fwdDist[step][x] += q;\n            } else {\n                fwdDist[step][x] += q * P;\n                fwdDist[step][y] += q * Q;\n            }\n        }\n    }\n}\n\n// Build a new string by one exact right-to-left best-response pass.\n// The produced score is exact for the produced string.\ndouble backwardPassConstruct(const string& s, string& ns) {\n    computeForwardDist(s);\n    ns = s;\n\n    double valNext[V], valCur[V];\n    for (int x = 0; x < V; x++) valNext[x] = 0.0;\n\n    for (int step = MAXL; step >= 1; step--) {\n        double reward = 401.0 - step;\n        double bestScore = -1e100;\n        double bestHit = -1.0;\n        int bestA = 0;\n\n        for (int a = 0; a < 4; a++) {\n            double sc = 0.0;\n            double hit = 0.0;\n            for (int x = 0; x < V; x++) {\n                double pr = fwdDist[step - 1][x];\n                if (pr < 1e-14) continue;\n                int y = nxtPos[x][a];\n                double lv = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n                sc += pr * lv;\n                if (y == target_id) hit += pr * Q;\n            }\n            if (sc > bestScore + 1e-12 ||\n                (fabs(sc - bestScore) <= 1e-12 && hit > bestHit + 1e-15)) {\n                bestScore = sc;\n                bestHit = hit;\n                bestA = a;\n            }\n        }\n\n        ns[step - 1] = DIRS[bestA];\n        for (int x = 0; x < V; x++) {\n            int y = nxtPos[x][bestA];\n            valCur[x] = P * valNext[x] + Q * (y == target_id ? reward : valNext[y]);\n        }\n        memcpy(valNext, valCur, sizeof(double) * V);\n    }\n\n    return valNext[start_id];\n}\n\ndouble localOptimize(string& s, int maxPasses, double endTime,\n                     const function<double()>& elapsed) {\n    double curScore = evaluateString(s);\n    for (int pass = 0; pass < maxPasses && elapsed() < endTime; pass++) {\n        string ns;\n        double newScore = backwardPassConstruct(s, ns);\n        if (newScore > curScore + 1e-12) {\n            s.swap(ns);\n            curScore = newScore;\n        } else {\n            break;\n        }\n    }\n    return curScore;\n}\n\nstring routeByPenalties(double turnPenalty, double unsafeTurnPenalty) {\n    static const double INF = 1e100;\n    const int S = V * 5; // lastdir 0..3, 4 = none\n    vector<double> dist(S, INF);\n    vector<int> prevState(S, -1), prevMove(S, -1);\n\n    using PDI = pair<double, int>;\n    priority_queue<PDI, vector<PDI>, greater<PDI>> pq;\n\n    int st = start_id * 5 + 4;\n    dist[st] = 0.0;\n    pq.push({0.0, st});\n\n    while (!pq.empty()) {\n        auto [cd, sid] = pq.top();\n        pq.pop();\n        if (cd != dist[sid]) continue;\n\n        int x = sid / 5;\n        int last = sid % 5;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[x][a];\n            if (y == x) continue;\n\n            double w = 1.0;\n            if (last < 4 && last != a) {\n                w += turnPenalty;\n                if (nxtPos[x][last] != x) w += unsafeTurnPenalty;\n            }\n\n            int nsid = y * 5 + a;\n            double nd = cd + w;\n            if (nd + 1e-12 < dist[nsid]) {\n                dist[nsid] = nd;\n                prevState[nsid] = sid;\n                prevMove[nsid] = a;\n                pq.push({nd, nsid});\n            }\n        }\n    }\n\n    double best = INF;\n    int goal = -1;\n    for (int last = 0; last < 5; last++) {\n        int sid = target_id * 5 + last;\n        if (dist[sid] < best) {\n            best = dist[sid];\n            goal = sid;\n        }\n    }\n    if (goal == -1 || best >= INF / 2) return \"\";\n\n    string path;\n    int cur = goal;\n    while (cur != st) {\n        path.push_back(DIRS[prevMove[cur]]);\n        cur = prevState[cur];\n    }\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nstring randomShortestPath(double straightBias, double wallBias) {\n    string path;\n    int cur = start_id;\n    int prev = 4;\n\n    while (cur != target_id) {\n        vector<int> cand;\n        vector<double> w;\n\n        for (int a = 0; a < 4; a++) {\n            int y = nxtPos[cur][a];\n            if (y == cur) continue;\n            if (distToTarget[y] != distToTarget[cur] - 1) continue;\n\n            double ww = 1.0;\n            if (a == prev) ww *= straightBias;\n            if (nxtPos[y][a] == y) ww *= wallBias;\n            ww *= 0.9 + 0.2 * rng.nextDouble();\n\n            cand.push_back(a);\n            w.push_back(ww);\n        }\n\n        if (cand.empty()) break;\n\n        double sum = 0.0;\n        for (double x : w) sum += x;\n        double r = rng.nextDouble() * sum;\n        int choose = cand.back();\n        for (int i = 0; i < (int)cand.size(); i++) {\n            if ((r -= w[i]) <= 0) {\n                choose = cand[i];\n                break;\n            }\n        }\n        path.push_back(DIRS[choose]);\n        cur = nxtPos[cur][choose];\n        prev = choose;\n    }\n    return path;\n}\n\nstring makeTemplate(const string& path, int baseRep, int preTurnBonus, int postTurnBonus) {\n    string s;\n    for (int i = 0; i < (int)path.size() && (int)s.size() < MAXL; i++) {\n        int rep = baseRep;\n        if (i + 1 < (int)path.size() && path[i] != path[i + 1]) rep += preTurnBonus;\n        if (i > 0 && path[i - 1] != path[i]) rep += postTurnBonus;\n        for (int k = 0; k < rep && (int)s.size() < MAXL; k++) s.push_back(path[i]);\n    }\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> P;\n    Q = 1.0 - P;\n    for (int i = 0; i < N; i++) cin >> hwall[i];\n    for (int i = 0; i < N - 1; i++) cin >> vwall[i];\n\n    start_id = id(si, sj);\n    target_id = id(ti, tj);\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\n    buildTransitions();\n    bfsTargetDist();\n    buildAdaptiveDP();\n\n    double bestScore = -1.0;\n    string bestAns;\n    unordered_set<string> tried;\n\n    auto submitCandidate = [&](string s, int passes) {\n        if ((int)s.size() < MAXL) s = completeByGreedy(s, true);\n        if ((int)s.size() > MAXL) s.resize(MAXL);\n        if ((int)s.size() < MAXL) s += string(MAXL - s.size(), 'D');\n        if (!tried.insert(s).second) return;\n\n        double sc = localOptimize(s, passes, 1.95, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    };\n\n    // Baseline greedy completions\n    {\n        State init = initialState();\n        State g1 = greedyComplete(init, false);\n        submitCandidate(toString(g1), 6);\n\n        State g2 = greedyComplete(init, true);\n        submitCandidate(toString(g2), 6);\n    }\n\n    // Path-based candidates: explicitly diversify by turn / unsafe-turn penalties\n    vector<pair<double, double>> penaltyList = {\n        {0.0, 0.0},\n        {0.3, 0.0},\n        {0.8, 0.0},\n        {1.5, 0.0},\n        {0.4, 1.0},\n        {0.8, 2.0},\n        {1.2, 3.0},\n        {2.0, 4.0}\n    };\n\n    vector<string> paths;\n    for (auto [tp, up] : penaltyList) {\n        string path = routeByPenalties(tp, up);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Randomized shortest paths\n    for (int k = 0; k < 8; k++) {\n        double sb = 1.5 + 1.0 * rng.nextDouble();\n        double wb = 1.2 + 1.5 * rng.nextDouble();\n        string path = randomShortestPath(sb, wb);\n        if (!path.empty() && (int)path.size() <= MAXL) paths.push_back(path);\n    }\n\n    // Path templates\n    for (const string& path : paths) {\n        submitCandidate(path, 5);\n        submitCandidate(makeTemplate(path, 2, 0, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 0), 5);\n        submitCandidate(makeTemplate(path, 1, 1, 1), 5);\n        submitCandidate(makeTemplate(path, 2, 1, 0), 5);\n        if (P >= 0.30) submitCandidate(makeTemplate(path, 3, 0, 0), 4);\n        if (P >= 0.35) submitCandidate(makeTemplate(path, 2, 1, 1), 4);\n    }\n\n    // Beam search with pruning by current best score\n    {\n        vector<State> beam, cand;\n        beam.reserve(500);\n        cand.reserve(2500);\n        beam.push_back(initialState());\n\n        auto cmpState = [](const State& a, const State& b) {\n            if (fabs(a.pri - b.pri) > 1e-12) return a.pri > b.pri;\n            if (fabs(a.upper - b.upper) > 1e-12) return a.upper > b.upper;\n            return a.score > b.score;\n        };\n\n        for (int step = 1; step <= MAXL; step++) {\n            if (elapsed() > 1.15) break;\n\n            int width;\n            if (step <= 40) width = 360;\n            else if (step <= 100) width = 280;\n            else width = 220;\n\n            cand.clear();\n            for (const State& st : beam) {\n                if (st.upper + 1e-12 < bestScore) continue;\n                for (int a = 0; a < 4; a++) {\n                    State nx = extendState(st, a, step);\n                    if (nx.upper + 1e-12 < bestScore) continue;\n                    cand.push_back(std::move(nx));\n                }\n            }\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(cand.begin(), cand.begin() + width, cand.end(), cmpState);\n                cand.resize(width);\n            }\n            sort(cand.begin(), cand.end(), cmpState);\n            beam.swap(cand);\n\n            if (!beam.empty() && (step <= 20 || step % 12 == 0)) {\n                int tries = min<int>(3, beam.size());\n                for (int i = 0; i < tries; i++) {\n                    string s1 = completeByGreedy(toString(beam[i]), true);\n                    submitCandidate(s1, 4);\n                    if (elapsed() > 1.20) break;\n                }\n            }\n        }\n\n        int tries = min<int>(8, beam.size());\n        for (int i = 0; i < tries && elapsed() < 1.35; i++) {\n            string s = completeByGreedy(toString(beam[i]), true);\n            submitCandidate(s, 5);\n        }\n    }\n\n    // Re-optimize best once more\n    if (!bestAns.empty() && elapsed() < 1.50) {\n        string s = bestAns;\n        double sc = localOptimize(s, 8, 1.60, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    // Random perturb + re-optimize\n    while (elapsed() < 1.96 && !bestAns.empty()) {\n        string s = bestAns;\n\n        int mode = rng.nextInt(0, 2);\n        if (mode == 0) {\n            int m = rng.nextInt(1, 3);\n            for (int t = 0; t < m; t++) {\n                int pos = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.8) * MAXL));\n                s[pos] = DIRS[rng.nextInt(0, 3)];\n            }\n        } else if (mode == 1) {\n            int l = min(MAXL - 1, (int)(pow(rng.nextDouble(), 1.7) * MAXL));\n            int len = rng.nextInt(2, 8);\n            char c = DIRS[rng.nextInt(0, 3)];\n            for (int i = l; i < min(MAXL, l + len); i++) s[i] = c;\n        } else {\n            int l = rng.nextInt(0, MAXL - 1);\n            int r = rng.nextInt(l, min(MAXL - 1, l + 10));\n            for (int i = l; i <= r; i++) s[i] = DIRS[rng.nextInt(0, 3)];\n        }\n\n        double sc = localOptimize(s, 3, 1.96, elapsed);\n        if (sc > bestScore + 1e-12) {\n            bestScore = sc;\n            bestAns = s;\n        }\n    }\n\n    if (bestAns.empty()) {\n        State init = initialState();\n        State g = greedyComplete(init, true);\n        bestAns = toString(g);\n    }\n\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc010":"#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    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int CELLS = N * N;\nstatic constexpr int SIDES = CELLS * 4;\n\nstatic constexpr int di[4] = {0, -1, 0, 1};\nstatic constexpr int dj[4] = {-1, 0, 1, 0};\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int ROT[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nstatic constexpr int PARTNER[8][4] = {\n    {1, 0, -1, -1},\n    {3, -1, -1, 0},\n    {-1, -1, 3, 2},\n    {-1, 2, 1, -1},\n    {1, 0, 3, 2},\n    {3, 2, 1, 0},\n    {2, -1, 0, -1},\n    {-1, 3, -1, 1},\n};\n\nstruct Eval {\n    long long official = 0;\n    long long sumsq = 0;\n    int top1 = 0;\n    int top2 = 0;\n    int totalCycle = 0;\n    int loops = 0;\n    int broken = 0;\n    int conn = 0;\n};\n\nstruct Candidate {\n    array<uint8_t, CELLS> st{};\n    Eval ev;\n};\n\nstruct Solver {\n    array<string, N> input{};\n    array<uint8_t, CELLS> orig{};\n    uint8_t cand[CELLS][4]{};\n    uint8_t candCnt[CELLS]{};\n    int rotTo[8][8];\n    int mask[8];\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n    const double TIME_LIMIT = 1.95;\n\n    Solver() {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng = XorShift64(seed);\n\n        memset(rotTo, -1, sizeof(rotTo));\n        for (int t = 0; t < 8; t++) {\n            int cur = t;\n            for (int k = 0; k < 4; k++) {\n                if (rotTo[t][cur] == -1) rotTo[t][cur] = k;\n                cur = ROT[cur];\n            }\n        }\n\n        for (int s = 0; s < 8; s++) {\n            int m = 0;\n            for (int d = 0; d < 4; d++) if (PARTNER[s][d] != -1) m |= (1 << d);\n            mask[s] = m;\n        }\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void read_input() {\n        for (int i = 0; i < N; i++) cin >> input[i];\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = input[i][j] - '0';\n                orig[p] = (uint8_t)t;\n                if (0 <= t && t <= 3) {\n                    candCnt[p] = 4;\n                    cand[p][0] = 0;\n                    cand[p][1] = 1;\n                    cand[p][2] = 2;\n                    cand[p][3] = 3;\n                } else if (t == 4 || t == 5) {\n                    candCnt[p] = 2;\n                    cand[p][0] = 4;\n                    cand[p][1] = 5;\n                } else {\n                    candCnt[p] = 2;\n                    cand[p][0] = 6;\n                    cand[p][1] = 7;\n                }\n            }\n        }\n    }\n\n    inline bool used(int s, int d) const {\n        return (mask[s] >> d) & 1;\n    }\n\n    inline uint8_t randCand(int pos) {\n        return cand[pos][rng.next_int(candCnt[pos])];\n    }\n\n    int localCellScore(const array<uint8_t, CELLS>& st, int pos, int ns) const {\n        int i = pos / N;\n        int j = pos % N;\n        int sc = 0;\n        int m = mask[ns];\n        for (int d = 0; d < 4; d++) {\n            bool u = (m >> d) & 1;\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (u) sc -= 3;\n            } else {\n                int np = ni * N + nj;\n                bool v = used(st[np], opp[d]);\n                if (u && v) sc += 2;\n                else if (u ^ v) sc -= 3;\n            }\n        }\n        return sc;\n    }\n\n    void localGreedy(array<uint8_t, CELLS>& st, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            bool changed = false;\n            for (int z = 0; z < CELLS; z++) {\n                int pos = order[z];\n                uint8_t cur = st[pos];\n                int bestSc = localCellScore(st, pos, cur);\n                uint8_t best = cur;\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == cur) continue;\n                    int sc = localCellScore(st, pos, ns);\n                    if (sc > bestSc || (sc == bestSc && rng.next_int(2) == 0)) {\n                        bestSc = sc;\n                        best = ns;\n                    }\n                }\n                if (best != cur) {\n                    st[pos] = best;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    Eval evaluate(const array<uint8_t, CELLS>& st) const {\n        Eval res;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int s = st[p];\n\n                if (j == 0 && used(s, 0)) { res.broken++; res.conn -= 3; }\n                if (i == 0 && used(s, 1)) { res.broken++; res.conn -= 3; }\n                if (j == N - 1 && used(s, 2)) { res.broken++; res.conn -= 3; }\n                if (i == N - 1 && used(s, 3)) { res.broken++; res.conn -= 3; }\n\n                if (j + 1 < N) {\n                    int q = i * N + (j + 1);\n                    bool a = used(st[p], 2);\n                    bool b = used(st[q], 0);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n                if (i + 1 < N) {\n                    int q = (i + 1) * N + j;\n                    bool a = used(st[p], 3);\n                    bool b = used(st[q], 1);\n                    if (a && b) res.conn += 2;\n                    else if (a ^ b) { res.broken++; res.conn -= 3; }\n                }\n            }\n        }\n\n        static uint8_t vis[SIDES];\n        static int stackv[SIDES];\n        memset(vis, 0, sizeof(vis));\n\n        for (int c = 0; c < CELLS; c++) {\n            int s = st[c];\n            for (int d = 0; d < 4; d++) {\n                if (!used(s, d)) continue;\n                int root = c * 4 + d;\n                if (vis[root]) continue;\n\n                int sp = 0;\n                stackv[sp++] = root;\n                vis[root] = 1;\n\n                int cnt = 0;\n                bool all2 = true;\n\n                while (sp) {\n                    int id = stackv[--sp];\n                    int cc = id >> 2;\n                    int dd = id & 3;\n                    int ss = st[cc];\n                    cnt++;\n\n                    int deg = 1;\n                    int i = cc / N;\n                    int j = cc % N;\n                    int ni = i + di[dd];\n                    int nj = j + dj[dd];\n                    bool ext = false;\n                    if (0 <= ni && ni < N && 0 <= nj && nj < N) {\n                        int nc = ni * N + nj;\n                        if (used(st[nc], opp[dd])) ext = true;\n                    }\n                    if (ext) deg++;\n                    if (deg != 2) all2 = false;\n\n                    int pd = PARTNER[ss][dd];\n                    int nid1 = cc * 4 + pd;\n                    if (!vis[nid1]) {\n                        vis[nid1] = 1;\n                        stackv[sp++] = nid1;\n                    }\n\n                    if (ext) {\n                        int nc = ni * N + nj;\n                        int nid2 = nc * 4 + opp[dd];\n                        if (!vis[nid2]) {\n                            vis[nid2] = 1;\n                            stackv[sp++] = nid2;\n                        }\n                    }\n                }\n\n                if (all2) {\n                    int len = cnt / 2;\n                    res.loops++;\n                    res.totalCycle += len;\n                    res.sumsq += 1LL * len * len;\n                    if (len > res.top1) {\n                        res.top2 = res.top1;\n                        res.top1 = len;\n                    } else if (len > res.top2) {\n                        res.top2 = len;\n                    }\n                }\n            }\n        }\n\n        if (res.loops >= 2) res.official = 1LL * res.top1 * res.top2;\n        else res.official = 0;\n        return res;\n    }\n\n    bool better(const Eval& a, const Eval& b) const {\n        if (a.official != b.official) return a.official > b.official;\n        if (a.top2 != b.top2) return a.top2 > b.top2;\n        if (a.top1 != b.top1) return a.top1 > b.top1;\n        if (a.sumsq != b.sumsq) return a.sumsq > b.sumsq;\n        if (a.totalCycle != b.totalCycle) return a.totalCycle > b.totalCycle;\n        if (a.conn != b.conn) return a.conn > b.conn;\n        if (a.broken != b.broken) return a.broken < b.broken;\n        return a.loops > b.loops;\n    }\n\n    array<uint8_t, CELLS> makeSeed(int mode) {\n        array<uint8_t, CELLS> st{};\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = i * N + j;\n                int t = orig[p];\n\n                if (mode == 0) {\n                    st[p] = orig[p];\n                } else if (mode == 1) {\n                    st[p] = randCand(p);\n                } else if (mode == 2) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 3) {\n                    if (t == 4 || t == 5) st[p] = ((i + j) & 1) ? 5 : 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 4) {\n                    if (t == 4 || t == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                } else if (mode == 5) {\n                    if (t == 4 || t == 5) st[p] = 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 6) {\n                    if (t == 6 || t == 7) st[p] = (j & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else if (mode == 7) {\n                    if (t == 6 || t == 7) st[p] = (i & 1) ? 6 : 7;\n                    else st[p] = randCand(p);\n                } else if (mode == 8) {\n                    if (t == 4 || t == 5) st[p] = (i & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else if (mode == 9) {\n                    if (t == 4 || t == 5) st[p] = (j & 1) ? 4 : 5;\n                    else st[p] = randCand(p);\n                } else {\n                    st[p] = randCand(p);\n                }\n            }\n        }\n        localGreedy(st, 6);\n        return st;\n    }\n\n    void exact1CellHill(array<uint8_t, CELLS>& st, Eval& cur, int sweeps) {\n        static array<int, CELLS> order;\n        for (int i = 0; i < CELLS; i++) order[i] = i;\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            if (elapsed() > TIME_LIMIT) return;\n\n            for (int i = CELLS - 1; i >= 1; i--) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n\n            bool changed = false;\n            for (int ii = 0; ii < CELLS; ii++) {\n                if (elapsed() > TIME_LIMIT) return;\n\n                int pos = order[ii];\n                uint8_t old = st[pos];\n                uint8_t bestState = old;\n                Eval bestEv = cur;\n\n                int curLS = localCellScore(st, pos, old);\n\n                for (int k = 0; k < candCnt[pos]; k++) {\n                    uint8_t ns = cand[pos][k];\n                    if (ns == old) continue;\n\n                    int newLS = localCellScore(st, pos, ns);\n                    if (newLS + 10 < curLS) continue;\n\n                    st[pos] = ns;\n                    Eval ev = evaluate(st);\n                    if (better(ev, bestEv)) {\n                        bestEv = ev;\n                        bestState = ns;\n                    }\n                }\n\n                st[pos] = bestState;\n                if (bestState != old) {\n                    cur = bestEv;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool improveRandom2x2(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            int p[4] = {\n                i * N + j,\n                i * N + (j + 1),\n                (i + 1) * N + j,\n                (i + 1) * N + (j + 1)\n            };\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]], old3 = st[p[3]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2, b3 = old3;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        for (int d = 0; d < candCnt[p[3]]; d++) {\n                            st[p[3]] = cand[p[3]][d];\n                            Eval ev = evaluate(st);\n                            if (better(ev, bestEv)) {\n                                bestEv = ev;\n                                b0 = st[p[0]];\n                                b1 = st[p[1]];\n                                b2 = st[p[2]];\n                                b3 = st[p[3]];\n                            }\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n            st[p[3]] = b3;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n                st[p[3]] = old3;\n            }\n        }\n        return any;\n    }\n\n    bool improveRandomLine3(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            bool horizontal = rng.next_int(2) == 0;\n            int p[3];\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                p[0] = i * N + j;\n                p[1] = i * N + (j + 1);\n                p[2] = i * N + (j + 2);\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                p[0] = i * N + j;\n                p[1] = (i + 1) * N + j;\n                p[2] = (i + 2) * N + j;\n            }\n\n            uint8_t old0 = st[p[0]], old1 = st[p[1]], old2 = st[p[2]];\n            Eval bestEv = cur;\n            uint8_t b0 = old0, b1 = old1, b2 = old2;\n\n            for (int a = 0; a < candCnt[p[0]]; a++) {\n                st[p[0]] = cand[p[0]][a];\n                for (int b = 0; b < candCnt[p[1]]; b++) {\n                    st[p[1]] = cand[p[1]][b];\n                    for (int c = 0; c < candCnt[p[2]]; c++) {\n                        st[p[2]] = cand[p[2]][c];\n                        Eval ev = evaluate(st);\n                        if (better(ev, bestEv)) {\n                            bestEv = ev;\n                            b0 = st[p[0]];\n                            b1 = st[p[1]];\n                            b2 = st[p[2]];\n                        }\n                    }\n                }\n            }\n\n            st[p[0]] = b0;\n            st[p[1]] = b1;\n            st[p[2]] = b2;\n\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                st[p[0]] = old0;\n                st[p[1]] = old1;\n                st[p[2]] = old2;\n            }\n        }\n        return any;\n    }\n\n    bool improveRandomRect23(array<uint8_t, CELLS>& st, Eval& cur, int tries) {\n        bool any = false;\n        for (int tt = 0; tt < tries; tt++) {\n            if (elapsed() > TIME_LIMIT) return any;\n\n            bool horizontal = rng.next_int(2) == 0;\n            vector<int> pos;\n            if (horizontal) {\n                int i = rng.next_int(N - 1);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 2; x++) for (int y = 0; y < 3; y++) pos.push_back((i + x) * N + (j + y));\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N - 1);\n                for (int x = 0; x < 3; x++) for (int y = 0; y < 2; y++) pos.push_back((i + x) * N + (j + y));\n            }\n\n            int prod = 1;\n            for (int p : pos) {\n                prod *= candCnt[p];\n                if (prod > 768) break;\n            }\n            if (prod > 768) continue;\n\n            array<uint8_t, 6> oldv{}, bestv{};\n            for (int i = 0; i < 6; i++) oldv[i] = bestv[i] = st[pos[i]];\n            Eval bestEv = cur;\n\n            function<void(int)> dfs = [&](int idx) {\n                if (elapsed() > TIME_LIMIT) return;\n                if (idx == 6) {\n                    Eval ev = evaluate(st);\n                    if (better(ev, bestEv)) {\n                        bestEv = ev;\n                        for (int i = 0; i < 6; i++) bestv[i] = st[pos[i]];\n                    }\n                    return;\n                }\n                int p = pos[idx];\n                for (int k = 0; k < candCnt[p]; k++) {\n                    st[p] = cand[p][k];\n                    dfs(idx + 1);\n                }\n            };\n\n            dfs(0);\n\n            for (int i = 0; i < 6; i++) st[pos[i]] = bestv[i];\n            if (better(bestEv, cur)) {\n                cur = bestEv;\n                any = true;\n            } else {\n                for (int i = 0; i < 6; i++) st[pos[i]] = oldv[i];\n            }\n        }\n        return any;\n    }\n\n    void mutate(array<uint8_t, CELLS>& st) {\n        int style = rng.next_int(7);\n\n        if (style == 0) {\n            int k = 2 + rng.next_int(10);\n            for (int t = 0; t < k; t++) {\n                int p = rng.next_int(CELLS);\n                st[p] = randCand(p);\n            }\n        } else if (style == 1) {\n            int h = 2 + rng.next_int(4);\n            int w = 2 + rng.next_int(4);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    if (st[p] == 4) st[p] = 5;\n                    else if (st[p] == 5) st[p] = 4;\n                    else st[p] = randCand(p);\n                }\n            }\n        } else if (style == 2) {\n            int row = rng.next_int(N);\n            for (int j = 0; j < N; j++) {\n                int p = row * N + j;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 3) {\n            int col = rng.next_int(N);\n            for (int i = 0; i < N; i++) {\n                int p = i * N + col;\n                if (rng.next_int(3) == 0) st[p] = randCand(p);\n            }\n        } else if (style == 4) {\n            int i = rng.next_int(N - 1);\n            int j = rng.next_int(N - 1);\n            for (int x = 0; x < 2; x++) for (int y = 0; y < 2; y++) {\n                int p = (i + x) * N + (j + y);\n                st[p] = randCand(p);\n            }\n        } else if (style == 5) {\n            bool horizontal = rng.next_int(2) == 0;\n            if (horizontal) {\n                int i = rng.next_int(N);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 3; x++) st[i * N + (j + x)] = randCand(i * N + (j + x));\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N);\n                for (int x = 0; x < 3; x++) st[(i + x) * N + j] = randCand((i + x) * N + j);\n            }\n        } else {\n            bool horizontal = rng.next_int(2) == 0;\n            if (horizontal) {\n                int i = rng.next_int(N - 1);\n                int j = rng.next_int(N - 2);\n                for (int x = 0; x < 2; x++) for (int y = 0; y < 3; y++) {\n                    int p = (i + x) * N + (j + y);\n                    if ((st[p] == 4 || st[p] == 5) && rng.next_int(2)) st[p] = (st[p] == 4 ? 5 : 4);\n                    else st[p] = randCand(p);\n                }\n            } else {\n                int i = rng.next_int(N - 2);\n                int j = rng.next_int(N - 1);\n                for (int x = 0; x < 3; x++) for (int y = 0; y < 2; y++) {\n                    int p = (i + x) * N + (j + y);\n                    if ((st[p] == 4 || st[p] == 5) && rng.next_int(2)) st[p] = (st[p] == 4 ? 5 : 4);\n                    else st[p] = randCand(p);\n                }\n            }\n        }\n    }\n\n    Candidate crossoverChild(const Candidate& A, const Candidate& B) {\n        Candidate c = A;\n        int style = rng.next_int(4);\n\n        if (style == 0) {\n            int h = 2 + rng.next_int(8);\n            int w = 2 + rng.next_int(8);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else if (style == 1) {\n            int si = rng.next_int(N);\n            int h = 1 + rng.next_int(N - si);\n            for (int i = si; i < si + h; i++) {\n                for (int j = 0; j < N; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else if (style == 2) {\n            int sj = rng.next_int(N);\n            int w = 1 + rng.next_int(N - sj);\n            for (int i = 0; i < N; i++) {\n                for (int j = sj; j < sj + w; j++) {\n                    int p = i * N + j;\n                    c.st[p] = B.st[p];\n                }\n            }\n        } else {\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    if (((i + j) & 1) == 0) {\n                        int p = i * N + j;\n                        c.st[p] = B.st[p];\n                    }\n                }\n            }\n        }\n\n        localGreedy(c.st, 2);\n        c.ev = evaluate(c.st);\n        return c;\n    }\n\n    void addElite(vector<Candidate>& elite, const Candidate& c, int limit = 7) {\n        elite.push_back(c);\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n        if ((int)elite.size() > limit) elite.resize(limit);\n    }\n\n    string solve() {\n        start_time = chrono::steady_clock::now();\n        vector<Candidate> elite;\n\n        {\n            Candidate c;\n            c.st = orig;\n            c.ev = evaluate(c.st);\n            addElite(elite, c);\n        }\n\n        for (int mode = 0; mode <= 9; mode++) {\n            if (elapsed() > 0.35) break;\n            Candidate c;\n            c.st = makeSeed(mode);\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            improveRandomLine3(c.st, c.ev, 6);\n            improveRandom2x2(c.st, c.ev, 6);\n            improveRandomRect23(c.st, c.ev, 2);\n            addElite(elite, c);\n        }\n\n        while (elapsed() < 0.75) {\n            Candidate c;\n            c.st = makeSeed(1 + rng.next_int(10));\n            c.ev = evaluate(c.st);\n            exact1CellHill(c.st, c.ev, 1);\n            addElite(elite, c);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        for (int id = 0; id < (int)elite.size(); id++) {\n            if (elapsed() > 1.10) break;\n            exact1CellHill(elite[id].st, elite[id].ev, 1);\n            improveRandomLine3(elite[id].st, elite[id].ev, 10);\n            improveRandom2x2(elite[id].st, elite[id].ev, 10);\n            improveRandomRect23(elite[id].st, elite[id].ev, 3);\n            exact1CellHill(elite[id].st, elite[id].ev, 1);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        while (elapsed() < TIME_LIMIT) {\n            int mode = rng.next_int(100);\n            Candidate cur;\n\n            if (mode < 25 && (int)elite.size() >= 2) {\n                int a = rng.next_int((int)elite.size());\n                int b = rng.next_int((int)elite.size() - 1);\n                if (b >= a) b++;\n                cur = crossoverChild(elite[a], elite[b]);\n            } else {\n                int idx;\n                int r = rng.next_int(100);\n                if (r < 50) idx = 0;\n                else if (r < 75) idx = min<int>(1, (int)elite.size() - 1);\n                else idx = rng.next_int((int)elite.size());\n\n                cur = elite[idx];\n                mutate(cur.st);\n                localGreedy(cur.st, 2);\n                cur.ev = evaluate(cur.st);\n            }\n\n            exact1CellHill(cur.st, cur.ev, 1);\n            improveRandomLine3(cur.st, cur.ev, 6 + rng.next_int(6));\n            improveRandom2x2(cur.st, cur.ev, 6 + rng.next_int(6));\n            improveRandomRect23(cur.st, cur.ev, 1 + rng.next_int(3));\n\n            if (rng.next_int(100) < 35) {\n                exact1CellHill(cur.st, cur.ev, 1);\n            }\n\n            addElite(elite, cur);\n        }\n\n        sort(elite.begin(), elite.end(), [&](const Candidate& a, const Candidate& b) {\n            return better(a.ev, b.ev);\n        });\n\n        const auto& best = elite[0].st;\n        string ans;\n        ans.reserve(CELLS);\n        for (int p = 0; p < CELLS; p++) {\n            int t = orig[p];\n            int s = best[p];\n            int r = rotTo[t][s];\n            if (r < 0) r = 0;\n            ans.push_back(char('0' + r));\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXM = 100;\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\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 XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l));\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\nstatic inline char opposite(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    if (c == 'R') return 'L';\n    return 0;\n}\n\nstatic inline int move_index(char c) {\n    if (c == 0) return 0;\n    if (c == 'U') return 1;\n    if (c == 'D') return 2;\n    if (c == 'L') return 3;\n    return 4;\n}\n\nstatic inline int next_pos(int empty, char mv, int N) {\n    if (mv == 'U') return empty - N;\n    if (mv == 'D') return empty + N;\n    if (mv == 'L') return empty - 1;\n    return empty + 1;\n}\n\nstruct FastDepthTable {\n    static constexpr int LOG = 21;\n    static constexpr int SZ = 1 << LOG;\n    static constexpr int MASK = SZ - 1;\n\n    vector<uint64_t> key;\n    vector<uint16_t> dep;\n    vector<uint8_t> used;\n\n    FastDepthTable() : key(SZ), dep(SZ), used(SZ, 0) {}\n\n    inline bool prune(uint64_t k, int d) {\n        uint64_t h = splitmix64(k);\n        int idx = (int)(h & MASK);\n        while (true) {\n            if (!used[idx]) {\n                used[idx] = 1;\n                key[idx] = k;\n                dep[idx] = (uint16_t)d;\n                return false;\n            }\n            if (key[idx] == k) {\n                if ((int)dep[idx] < d) return true;\n                if ((int)dep[idx] > d) dep[idx] = (uint16_t)d;\n                return false;\n            }\n            idx = (idx + 1) & MASK;\n        }\n    }\n};\n\nstruct Metrics {\n    int largestTree = 0;\n    int largestCC = 0;\n    int largestCCCycles = 0;\n    int cycleExcess = 0;\n    int matchedEdges = 0;\n    int bestPotential = 0;\n    int components = 0;\n};\n\nstruct State {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Cand {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    uint64_t stateKey = 0;\n    int empty = 0;\n    int parent = -1;\n    char prevMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct BestRef {\n    bool isTemp = false;\n    int nodeIdx = 0;\n    int parent = -1;\n    char lastMove = 0;\n    int depth = 0;\n    Metrics mt;\n};\n\nstruct Elite {\n    array<uint8_t, MAXM> board{};\n    uint64_t hash = 0;\n    int empty = 0;\n    char prevMove = 0;\n    int depth = 0;\n    string prefix;\n    Metrics mt;\n};\n\nMetrics evaluateBoard(const array<uint8_t, MAXM>& board, int N) {\n    const int M = N * N;\n    static uint8_t deg[MAXM];\n    static uint8_t vis[MAXM];\n    static int adj[MAXM][4];\n    static int q[MAXM];\n\n    memset(deg, 0, M);\n    memset(vis, 0, M);\n\n    int matchedEdges = 0;\n\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 = board[id];\n            if (t == 0) continue;\n\n            if (c + 1 < N) {\n                int id2 = id + 1;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 4) && (u & 1)) {\n                    adj[id][deg[id]++] = id2;\n                    adj[id2][deg[id2]++] = id;\n                    matchedEdges++;\n                }\n            }\n            if (r + 1 < N) {\n                int id2 = id + N;\n                uint8_t u = board[id2];\n                if (u != 0 && (t & 8) && (u & 2)) {\n                    adj[id][deg[id]++] = id2;\n                    adj[id2][deg[id2]++] = id;\n                    matchedEdges++;\n                }\n            }\n        }\n    }\n\n    Metrics mt;\n    mt.matchedEdges = matchedEdges;\n\n    for (int s = 0; s < M; s++) {\n        if (board[s] == 0 || vis[s]) continue;\n        mt.components++;\n\n        int head = 0, tail = 0;\n        q[tail++] = s;\n        vis[s] = 1;\n\n        int v = 0;\n        int sumDeg = 0;\n\n        while (head < tail) {\n            int u = q[head++];\n            v++;\n            sumDeg += deg[u];\n            for (int k = 0; k < deg[u]; k++) {\n                int to = adj[u][k];\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        int e = sumDeg >> 1;\n        int cyc = max(0, e - v + 1);\n        mt.cycleExcess += cyc;\n        if (e == v - 1) mt.largestTree = max(mt.largestTree, v);\n        if (v > mt.largestCC || (v == mt.largestCC && cyc < mt.largestCCCycles)) {\n            mt.largestCC = v;\n            mt.largestCCCycles = cyc;\n        }\n        mt.bestPotential = max(mt.bestPotential, 4 * v - 7 * cyc);\n    }\n\n    return mt;\n}\n\nbool betterReal(const Metrics& a, int depthA, const Metrics& b, int depthB, int fullSize) {\n    if (a.largestTree != b.largestTree) return a.largestTree > b.largestTree;\n    if (a.largestTree == fullSize && depthA != depthB) return depthA < depthB;\n    if (a.matchedEdges != b.matchedEdges) return a.matchedEdges > b.matchedEdges;\n    if (a.cycleExcess != b.cycleExcess) return a.cycleExcess < b.cycleExcess;\n    if (a.components != b.components) return a.components < b.components;\n    if (a.largestCC != b.largestCC) return a.largestCC > b.largestCC;\n    if (a.largestCCCycles != b.largestCCCycles) return a.largestCCCycles < b.largestCCCycles;\n    if (a.bestPotential != b.bestPotential) return a.bestPotential > b.bestPotential;\n    return false;\n}\n\nlong long keyTree(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 55) {\n        return 1'000'000'000'000LL * m.bestPotential\n             +   10'000'000'000LL * m.largestCC\n             +      100'000'000LL * m.matchedEdges\n             -        2'000'000LL * m.largestCCCycles\n             -        1'000'000LL * m.components\n             +           10'000LL * m.largestTree\n             -              100LL * m.cycleExcess;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   10'000'000'000LL * m.matchedEdges\n             -      100'000'000LL * m.cycleExcess\n             -       10'000'000LL * m.components\n             +        1'000'000LL * m.largestCC\n             -           10'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nlong long keyMatch(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   10'000'000'000LL * m.cycleExcess\n         -      500'000'000LL * m.components\n         +      100'000'000LL * m.largestCC\n         -        1'000'000LL * m.largestCCCycles\n         +           10'000LL * m.largestTree\n         +                1LL * m.bestPotential;\n}\n\nlong long keyFocus(const Metrics& m) {\n    return 1'000'000'000'000LL * m.matchedEdges\n         -   20'000'000'000LL * m.cycleExcess\n         -    1'000'000'000LL * m.components\n         +      500'000'000LL * m.largestTree\n         +       10'000'000LL * m.largestCC\n         -          100'000LL * m.largestCCCycles\n         +                1LL * m.bestPotential;\n}\n\nlong long keyDedup(const Metrics& m, int depth, int T) {\n    return max(keyTree(m, depth, T), keyMatch(m));\n}\n\nlong long keyRoll(const Metrics& m, int depth, int T) {\n    if (depth * 100 < T * 75) {\n        return 1'000'000'000'000LL * m.matchedEdges\n             -   15'000'000'000LL * m.cycleExcess\n             -      800'000'000LL * m.components\n             +      200'000'000LL * m.largestCC\n             +      100'000'000LL * m.largestTree\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    } else {\n        return 1'000'000'000'000LL * m.largestTree\n             +   20'000'000'000LL * m.matchedEdges\n             -   30'000'000'000LL * m.cycleExcess\n             -    2'000'000'000LL * m.components\n             +      100'000'000LL * m.largestCC\n             -        1'000'000LL * m.largestCCCycles\n             +                1LL * m.bestPotential;\n    }\n}\n\nstring reconstructPathFromNode(const vector<State>& nodes, int idx) {\n    string s;\n    while (idx > 0) {\n        s.push_back(nodes[idx].prevMove);\n        idx = nodes[idx].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    cin >> N >> T;\n    int M = N * N;\n    int FULL = M - 1;\n\n    array<uint8_t, MAXM> initBoard{};\n    int initEmpty = -1;\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            initBoard[i * N + j] = (uint8_t)v;\n            if (v == 0) initEmpty = i * N + j;\n        }\n    }\n\n    uint64_t zob[MAXM][16];\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < MAXM; i++) {\n        for (int j = 0; j < 16; j++) {\n            seed = splitmix64(seed);\n            zob[i][j] = seed;\n        }\n    }\n    uint64_t pmSalt[5];\n    for (int i = 0; i < 5; i++) {\n        seed = splitmix64(seed);\n        pmSalt[i] = seed;\n    }\n    auto makeStateKey = [&](uint64_t hash, char prevMove) -> uint64_t {\n        return hash ^ pmSalt[move_index(prevMove)];\n    };\n\n    uint64_t initHash = 0;\n    for (int i = 0; i < M; i++) initHash ^= zob[i][initBoard[i]];\n\n    Timer timer;\n    XorShift64 rng(initHash ^ 0x9e3779b97f4a7c15ULL);\n\n    State root;\n    root.board = initBoard;\n    root.hash = initHash;\n    root.empty = initEmpty;\n    root.parent = -1;\n    root.prevMove = 0;\n    root.depth = 0;\n    root.mt = evaluateBoard(root.board, N);\n\n    if (root.mt.largestTree == FULL) {\n        cout << '\\n';\n        return 0;\n    }\n\n    int beamWidth1, beamWidth2;\n    double timeStage1, timeStage2, totalTimeLimit;\n\n    if (N <= 7) {\n        beamWidth1 = 360;\n        beamWidth2 = 100;\n        timeStage1 = 1.86;\n        timeStage2 = 2.48;\n        totalTimeLimit = 2.86;\n    } else if (N == 8) {\n        beamWidth1 = 305;\n        beamWidth2 = 84;\n        timeStage1 = 1.76;\n        timeStage2 = 2.40;\n        totalTimeLimit = 2.82;\n    } else if (N == 9) {\n        beamWidth1 = 250;\n        beamWidth2 = 70;\n        timeStage1 = 1.67;\n        timeStage2 = 2.32;\n        totalTimeLimit = 2.78;\n    } else {\n        beamWidth1 = 205;\n        beamWidth2 = 56;\n        timeStage1 = 1.58;\n        timeStage2 = 2.24;\n        totalTimeLimit = 2.74;\n    }\n\n    vector<State> nodes;\n    nodes.reserve(1 + (beamWidth1 + beamWidth2) * (T + 8));\n    nodes.push_back(root);\n\n    FastDepthTable globalSeen;\n    globalSeen.prune(makeStateKey(root.hash, root.prevMove), 0);\n\n    vector<int> cur, nxt;\n    cur.push_back(0);\n\n    BestRef best;\n    best.isTemp = false;\n    best.nodeIdx = 0;\n    best.depth = 0;\n    best.mt = root.mt;\n\n    const char moves[4] = {'U', 'D', 'L', 'R'};\n    int depth = 0;\n\n    auto materializeAnswer = [&](const BestRef& b) -> string {\n        string ans;\n        if (b.isTemp) {\n            ans = reconstructPathFromNode(nodes, b.parent);\n            ans.push_back(b.lastMove);\n        } else {\n            ans = reconstructPathFromNode(nodes, b.nodeIdx);\n        }\n        if ((int)ans.size() > T) ans.resize(T);\n        return ans;\n    };\n\n    auto makeEliteFromNode = [&](int idx) -> Elite {\n        Elite e;\n        const State& s = nodes[idx];\n        e.board = s.board;\n        e.hash = s.hash;\n        e.empty = s.empty;\n        e.prevMove = s.prevMove;\n        e.depth = s.depth;\n        e.prefix = reconstructPathFromNode(nodes, idx);\n        e.mt = s.mt;\n        return e;\n    };\n\n    auto makeEliteFromBestRef = [&](const BestRef& b) -> Elite {\n        if (!b.isTemp) return makeEliteFromNode(b.nodeIdx);\n        Elite e;\n        const State& p = nodes[b.parent];\n        e.board = p.board;\n        e.hash = p.hash;\n        e.empty = p.empty;\n        e.prevMove = b.lastMove;\n        e.prefix = reconstructPathFromNode(nodes, b.parent);\n        e.prefix.push_back(b.lastMove);\n        e.depth = (int)e.prefix.size();\n\n        int np = next_pos(p.empty, b.lastMove, N);\n        uint8_t tile = e.board[np];\n        e.board[p.empty] = tile;\n        e.board[np] = 0;\n        e.empty = np;\n        e.hash = p.hash ^ zob[p.empty][0] ^ zob[np][tile] ^ zob[p.empty][tile] ^ zob[np][0];\n        e.mt = b.mt;\n        return e;\n    };\n\n    auto tryUpdateBestTemp = [&](const Metrics& mt, int nd, int parent, char mv) {\n        if (betterReal(mt, nd, best.mt, best.depth, FULL)) {\n            best.isTemp = true;\n            best.parent = parent;\n            best.lastMove = mv;\n            best.depth = nd;\n            best.mt = mt;\n        }\n    };\n\n    auto tryUpdateBestNode = [&](int nodeIdx) {\n        const State& s = nodes[nodeIdx];\n        if (betterReal(s.mt, s.depth, best.mt, best.depth, FULL)) {\n            best.isTemp = false;\n            best.nodeIdx = nodeIdx;\n            best.depth = s.depth;\n            best.mt = s.mt;\n        }\n    };\n\n    // Stage 1\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage1) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool stopNow = false;\n        for (int ii = 0; ii < (int)cur.size(); ii++) {\n            if ((ii & 31) == 0 && timer.elapsed() > timeStage1) {\n                stopNow = true;\n                break;\n            }\n            int idx = cur[ii];\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                uint8_t tile = st.board[np];\n                uint64_t nh = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                uint64_t sk = makeStateKey(nh, mv);\n                int nd = st.depth + 1;\n\n                if (globalSeen.prune(sk, nd)) continue;\n\n                Cand cd;\n                cd.board = st.board;\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.depth = nd;\n                cd.hash = nh;\n                cd.stateKey = sk;\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, cd.depth, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    cout << materializeAnswer(best) << '\\n';\n                    return 0;\n                }\n\n                auto it = seen.find(sk);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(sk, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyDedup(cd.mt, cd.depth, T) > keyDedup(cands[pos].mt, cands[pos].depth, T)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n        }\n        if (stopNow && cands.empty()) break;\n        if (cands.empty()) break;\n\n        int C = (int)cands.size();\n        vector<int> ordA(C), ordB(C);\n        iota(ordA.begin(), ordA.end(), 0);\n        iota(ordB.begin(), ordB.end(), 0);\n\n        sort(ordA.begin(), ordA.end(), [&](int x, int y) {\n            long long kx = keyTree(cands[x].mt, cands[x].depth, T);\n            long long ky = keyTree(cands[y].mt, cands[y].depth, T);\n            if (kx != ky) return kx > ky;\n            return keyMatch(cands[x].mt) > keyMatch(cands[y].mt);\n        });\n        sort(ordB.begin(), ordB.end(), [&](int x, int y) {\n            long long kx = keyMatch(cands[x].mt);\n            long long ky = keyMatch(cands[y].mt);\n            if (kx != ky) return kx > ky;\n            return keyTree(cands[x].mt, cands[x].depth, T) > keyTree(cands[y].mt, cands[y].depth, T);\n        });\n\n        vector<char> picked(C, 0);\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 4;\n\n        nxt.clear();\n        nxt.reserve(min(C, beamWidth1));\n\n        int pa = 0, pb = 0;\n        while ((int)nxt.size() < beamWidth1 && (pa < C || pb < C)) {\n            bool progressed = false;\n\n            while (pa < C) {\n                int id = ordA[pa++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n                progressed = true;\n                break;\n            }\n            if ((int)nxt.size() >= beamWidth1) break;\n\n            while (pb < C) {\n                int id = ordB[pb++];\n                if (picked[id]) continue;\n                if (emptyCnt[cands[id].empty] >= perEmptyLimit) continue;\n                picked[id] = 1;\n                emptyCnt[cands[id].empty]++;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n                progressed = true;\n                break;\n            }\n\n            if (!progressed) break;\n        }\n\n        if ((int)nxt.size() < beamWidth1) {\n            for (int t = 0; t < C && (int)nxt.size() < beamWidth1; t++) {\n                int id = ordA[t];\n                if (picked[id]) continue;\n                picked[id] = 1;\n                State ns;\n                ns.board = cands[id].board;\n                ns.hash = cands[id].hash;\n                ns.empty = cands[id].empty;\n                ns.parent = cands[id].parent;\n                ns.prevMove = cands[id].prevMove;\n                ns.depth = cands[id].depth;\n                ns.mt = cands[id].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    if (best.mt.largestTree == FULL) {\n        cout << materializeAnswer(best) << '\\n';\n        return 0;\n    }\n\n    // Stage 2\n    for (; depth < T; depth++) {\n        if (timer.elapsed() > timeStage2) break;\n        if (cur.empty()) break;\n\n        vector<Cand> cands;\n        cands.reserve(cur.size() * 3 + 8);\n        unordered_map<uint64_t, int> seen;\n        seen.reserve(cur.size() * 8 + 32);\n\n        bool stopNow = false;\n        for (int ii = 0; ii < (int)cur.size(); ii++) {\n            if ((ii & 31) == 0 && timer.elapsed() > timeStage2) {\n                stopNow = true;\n                break;\n            }\n            int idx = cur[ii];\n            const State& st = nodes[idx];\n            int e = st.empty;\n            int r = e / N, c = e % N;\n\n            for (char mv : moves) {\n                if (st.prevMove && mv == opposite(st.prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = e - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = e + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = e - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = e + 1;\n                }\n\n                uint8_t tile = st.board[np];\n                uint64_t nh = st.hash ^ zob[e][0] ^ zob[np][tile] ^ zob[e][tile] ^ zob[np][0];\n                uint64_t sk = makeStateKey(nh, mv);\n                int nd = st.depth + 1;\n\n                if (globalSeen.prune(sk, nd)) continue;\n\n                Cand cd;\n                cd.board = st.board;\n                cd.board[e] = tile;\n                cd.board[np] = 0;\n                cd.empty = np;\n                cd.parent = idx;\n                cd.prevMove = mv;\n                cd.depth = nd;\n                cd.hash = nh;\n                cd.stateKey = sk;\n                cd.mt = evaluateBoard(cd.board, N);\n\n                tryUpdateBestTemp(cd.mt, cd.depth, idx, mv);\n                if (cd.mt.largestTree == FULL) {\n                    cout << materializeAnswer(best) << '\\n';\n                    return 0;\n                }\n\n                auto it = seen.find(sk);\n                if (it == seen.end()) {\n                    int pos = (int)cands.size();\n                    seen.emplace(sk, pos);\n                    cands.push_back(std::move(cd));\n                } else {\n                    int pos = it->second;\n                    if (keyFocus(cd.mt) > keyFocus(cands[pos].mt)) {\n                        cands[pos] = std::move(cd);\n                    }\n                }\n            }\n        }\n        if (stopNow && cands.empty()) break;\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b) {\n            long long ka = keyFocus(a.mt);\n            long long kb = keyFocus(b.mt);\n            if (ka != kb) return ka > kb;\n            return keyTree(a.mt, a.depth, T) > keyTree(b.mt, b.depth, T);\n        });\n\n        nxt.clear();\n        nxt.reserve(min((int)cands.size(), beamWidth2));\n        vector<int> emptyCnt(M, 0);\n        int perEmptyLimit = 2;\n\n        for (auto& cd : cands) {\n            if ((int)nxt.size() >= beamWidth2) break;\n            if (emptyCnt[cd.empty] >= perEmptyLimit) continue;\n            emptyCnt[cd.empty]++;\n\n            State ns;\n            ns.board = cd.board;\n            ns.hash = cd.hash;\n            ns.empty = cd.empty;\n            ns.parent = cd.parent;\n            ns.prevMove = cd.prevMove;\n            ns.depth = cd.depth;\n            ns.mt = cd.mt;\n            int nid = (int)nodes.size();\n            nodes.push_back(std::move(ns));\n            nxt.push_back(nid);\n            tryUpdateBestNode(nid);\n        }\n\n        if (nxt.empty()) {\n            for (int i = 0; i < (int)cands.size() && (int)nxt.size() < beamWidth2; i++) {\n                State ns;\n                ns.board = cands[i].board;\n                ns.hash = cands[i].hash;\n                ns.empty = cands[i].empty;\n                ns.parent = cands[i].parent;\n                ns.prevMove = cands[i].prevMove;\n                ns.depth = cands[i].depth;\n                ns.mt = cands[i].mt;\n                int nid = (int)nodes.size();\n                nodes.push_back(std::move(ns));\n                nxt.push_back(nid);\n                tryUpdateBestNode(nid);\n            }\n        }\n\n        cur.swap(nxt);\n    }\n\n    string bestAns = materializeAnswer(best);\n    Metrics bestMt = best.mt;\n    int bestDepth = best.depth;\n\n    if (bestMt.largestTree == FULL || timer.elapsed() > totalTimeLimit - 0.04) {\n        if ((int)bestAns.size() > T) bestAns.resize(T);\n        cout << bestAns << '\\n';\n        return 0;\n    }\n\n    vector<Elite> elites;\n    {\n        vector<pair<long long, int>> ordF, ordT, ordM;\n        ordF.reserve(cur.size());\n        ordT.reserve(cur.size());\n        ordM.reserve(cur.size());\n\n        for (int idx : cur) {\n            ordF.push_back({keyFocus(nodes[idx].mt), idx});\n            ordT.push_back({keyTree(nodes[idx].mt, nodes[idx].depth, T), idx});\n            ordM.push_back({keyMatch(nodes[idx].mt), idx});\n        }\n        sort(ordF.begin(), ordF.end(), greater<>());\n        sort(ordT.begin(), ordT.end(), greater<>());\n        sort(ordM.begin(), ordM.end(), greater<>());\n\n        unordered_set<uint64_t> used;\n        used.reserve(32);\n\n        auto addNodeElite = [&](int idx) {\n            uint64_t k = makeStateKey(nodes[idx].hash, nodes[idx].prevMove);\n            if (used.insert(k).second) elites.push_back(makeEliteFromNode(idx));\n        };\n\n        for (int i = 0; i < min(4, (int)ordF.size()); i++) addNodeElite(ordF[i].second);\n        for (int i = 0; i < min(4, (int)ordT.size()); i++) addNodeElite(ordT[i].second);\n        for (int i = 0; i < min(3, (int)ordM.size()); i++) addNodeElite(ordM[i].second);\n\n        Elite eb = makeEliteFromBestRef(best);\n        if (used.insert(makeStateKey(eb.hash, eb.prevMove)).second) elites.push_back(std::move(eb));\n    }\n\n    struct Opt {\n        array<uint8_t, MAXM> board{};\n        uint64_t hash = 0;\n        int empty = 0;\n        char mv = 0;\n        Metrics mt;\n        long long key = 0;\n    };\n\n    auto eliteValue = [&](const Elite& e) {\n        return keyFocus(e.mt);\n    };\n\n    int rolloutTrials = 0;\n    int maxRolloutTrials = (N <= 7 ? 24 : (N == 8 ? 18 : (N == 9 ? 15 : 12)));\n\n    while (timer.elapsed() < totalTimeLimit && !elites.empty() && rolloutTrials < maxRolloutTrials) {\n        rolloutTrials++;\n\n        sort(elites.begin(), elites.end(), [&](const Elite& a, const Elite& b) {\n            return eliteValue(a) > eliteValue(b);\n        });\n\n        int pool = min(5, (int)elites.size());\n        int pickElite = rng.next_int(0, pool);\n        if ((rng.next() & 1ULL) == 0) pickElite = 0;\n\n        Elite base = elites[pickElite];\n\n        array<uint8_t, MAXM> board = base.board;\n        uint64_t hash = base.hash;\n        int empty = base.empty;\n        char prevMove = base.prevMove;\n        Metrics curMt = base.mt;\n        string suffix;\n        suffix.reserve(max(0, T - base.depth));\n\n        long long curKey = keyRoll(curMt, base.depth, T);\n        int stagnation = 0;\n        uint64_t recent[12];\n        int recentLen = 1, recentPos = 1;\n        recent[0] = makeStateKey(hash, prevMove);\n\n        int maxSuffix = min(T - base.depth, N <= 8 ? 48 : 36);\n\n        while ((int)suffix.size() < maxSuffix && base.depth + (int)suffix.size() < T && timer.elapsed() < totalTimeLimit) {\n            vector<Opt> opts;\n            opts.reserve(4);\n\n            int r = empty / N, c = empty % N;\n            for (char mv : moves) {\n                if (prevMove && mv == opposite(prevMove)) continue;\n\n                int np = -1;\n                if (mv == 'U') {\n                    if (r == 0) continue;\n                    np = empty - N;\n                } else if (mv == 'D') {\n                    if (r + 1 >= N) continue;\n                    np = empty + N;\n                } else if (mv == 'L') {\n                    if (c == 0) continue;\n                    np = empty - 1;\n                } else {\n                    if (c + 1 >= N) continue;\n                    np = empty + 1;\n                }\n\n                Opt op;\n                op.board = board;\n                uint8_t tile = op.board[np];\n                op.board[empty] = tile;\n                op.board[np] = 0;\n                op.empty = np;\n                op.mv = mv;\n                op.hash = hash ^ zob[empty][0] ^ zob[np][tile] ^ zob[empty][tile] ^ zob[np][0];\n                op.mt = evaluateBoard(op.board, N);\n                op.key = keyRoll(op.mt, base.depth + (int)suffix.size() + 1, T);\n\n                uint64_t rk = makeStateKey(op.hash, mv);\n                for (int i = 0; i < recentLen; i++) {\n                    if (recent[i] == rk) {\n                        op.key -= 50'000'000LL;\n                        break;\n                    }\n                }\n                op.key += (long long)(rng.next() % 1001) - 500;\n                opts.push_back(std::move(op));\n            }\n\n            if (opts.empty()) break;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.key > b.key; });\n\n            int pick = 0;\n            if ((int)opts.size() >= 2) {\n                uint64_t rv = rng.next() % 100;\n                if (stagnation < 8) pick = (rv < 84 ? 0 : 1);\n                else pick = (rv < 62 ? 0 : 1);\n            }\n\n            Opt chosen = std::move(opts[pick]);\n            board = chosen.board;\n            hash = chosen.hash;\n            empty = chosen.empty;\n            prevMove = chosen.mv;\n            curMt = chosen.mt;\n            suffix.push_back(chosen.mv);\n\n            recent[recentPos % 12] = makeStateKey(hash, prevMove);\n            recentPos++;\n            if (recentLen < 12) recentLen++;\n\n            long long nk = keyRoll(curMt, base.depth + (int)suffix.size(), T);\n            if (nk > curKey) stagnation = 0;\n            else stagnation++;\n            curKey = nk;\n\n            int totalDepth = base.depth + (int)suffix.size();\n            if (betterReal(curMt, totalDepth, bestMt, bestDepth, FULL)) {\n                bestMt = curMt;\n                bestDepth = totalDepth;\n                bestAns = base.prefix + suffix;\n                if ((int)bestAns.size() > T) bestAns.resize(T);\n                if (bestMt.largestTree == FULL) {\n                    cout << bestAns << '\\n';\n                    return 0;\n                }\n            }\n\n            if (stagnation >= 14 && (int)suffix.size() >= 8) break;\n        }\n    }\n\n    if ((int)bestAns.size() > T) bestAns.resize(T);\n    cout << bestAns << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr double R = 10000.0;\nstatic constexpr int MAXK = 100;\n\nstruct Point {\n    int x, y;\n};\n\nstruct Part {\n    int m = 1;\n    vector<int> bin;\n    vector<long long> cuts; // A x + B y = C\n};\n\nstruct Sol {\n    int score = -1;\n    int goodCells = -1;\n    int A1 = 0, B1 = 1; // family 1 normal\n    int A2 = 1, B2 = 0; // family 2 normal\n    int m1 = 1, m2 = 1;\n    vector<long long> cuts1, cuts2;\n};\n\nstatic inline bool better_pair(int sc, int good, int bestSc, int bestGood) {\n    if (sc != bestSc) return sc > bestSc;\n    return good > bestGood;\n}\nstatic inline bool better_sol(const Sol& a, const Sol& b) {\n    return better_pair(a.score, a.goodCells, b.score, b.goodCells);\n}\n\npair<int,int> normalize_vec(int x, int y) {\n    if (x == 0 && y == 0) return {1, 0};\n    int g = std::gcd(abs(x), abs(y));\n    x /= g;\n    y /= g;\n    if (x < 0 || (x == 0 && y < 0)) {\n        x = -x;\n        y = -y;\n    }\n    return {x, y};\n}\n\nlong long extgcd(long long a, long long b, long long &x, long long &y) {\n    if (b == 0) {\n        x = 1; y = 0;\n        return a;\n    }\n    long long x1, y1;\n    long long g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<long long,4> line_from_ABC(long long A, long long B, long long C) {\n    if (A == 0) {\n        long long y = C / B;\n        return {0, y, 1, y};\n    }\n    if (B == 0) {\n        long long x = C / A;\n        return {x, 0, x, 1};\n    }\n\n    long long x, y;\n    extgcd(llabs(A), llabs(B), x, y);\n    if (A < 0) x = -x;\n    if (B < 0) y = -y;\n\n    long long x0 = x * C;\n    long long y0 = y * C;\n\n    long double denom = (long double)A * A + (long double)B * B;\n    long double tt = ((long double)x0 * B - (long double)y0 * A) / denom;\n    long long t = llround(tt);\n\n    x0 -= B * t;\n    y0 += A * t;\n\n    long long x1 = x0, y1 = y0;\n    long long x2 = x0 - B, y2 = y0 + A;\n    return {x1, y1, x2, y2};\n}\n\nvector<double> select_lambdas(int N, const array<int,11>& a) {\n    vector<pair<double,double>> cand;\n    for (double lam = 0.8; lam <= 10.0 + 1e-9; lam += 0.2) {\n        double Mocc = N / lam;\n        double p = exp(-lam);\n        double score = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lam / d;\n            double bd = Mocc * p;\n            score += min<double>(a[d], bd);\n        }\n        cand.push_back({score, lam});\n    }\n    sort(cand.begin(), cand.end(), [&](auto &l, auto &r) {\n        return l.first > r.first;\n    });\n\n    vector<double> res;\n    for (auto [sc, lam] : cand) {\n        bool ok = true;\n        for (double x : res) {\n            if (abs(x - lam) < 0.35) { ok = false; break; }\n        }\n        if (ok) res.push_back(lam);\n        if ((int)res.size() >= 6) break;\n    }\n    if (res.empty()) res.push_back(5.0);\n    return res;\n}\n\nvector<pair<int,int>> generate_pairs(int N, int A, const array<int,11>& a, int cap = 84) {\n    const double PI = acos(-1.0);\n    vector<double> lambdas = select_lambdas(N, a);\n    set<pair<int,int>> st;\n\n    auto add_pair = [&](int m1, int m2) {\n        if (m1 < 1 || m2 < 1) return;\n        if (m1 + m2 - 2 > MAXK) return;\n        st.insert({m1, m2});\n    };\n\n    for (double lam : lambdas) {\n        double P = 4.0 * N / PI / lam;\n        vector<double> ratios = {1.0, 1.25, 1.4, 1.0 / 1.25, 1.0 / 1.4};\n\n        for (double ratio : ratios) {\n            int base1 = max(1, (int)llround(sqrt(P * ratio)));\n            for (int d1 = -2; d1 <= 2; d1++) {\n                int m1 = max(1, base1 + d1);\n                int base2 = max(1, (int)llround(P / m1));\n                for (int d2 = -2; d2 <= 2; d2++) {\n                    add_pair(m1, base2 + d2);\n                }\n            }\n        }\n    }\n\n    vector<int> oneD = {2,3,4,5,6,8,10,12,15,20,25,30,40,50,60,80,100};\n    for (int m : oneD) {\n        add_pair(1, m);\n        add_pair(m, 1);\n    }\n\n    {\n        const double PI2 = acos(-1.0);\n        double P = 4.0 * max(1, A) / PI2;\n        int b = max(1, (int)llround(sqrt(P)));\n        for (int d1 = -4; d1 <= 4; d1++) {\n            int m1 = max(1, b + d1);\n            int m2 = max(1, (int)llround(P / m1));\n            for (int d2 = -3; d2 <= 3; d2++) add_pair(m1, m2 + d2);\n        }\n    }\n\n    vector<pair<int,int>> res(st.begin(), st.end());\n    sort(res.begin(), res.end(), [&](auto &L, auto &Rr) {\n        long long pL = 1LL * L.first * L.second;\n        long long pR = 1LL * Rr.first * Rr.second;\n        return pL > pR;\n    });\n    if ((int)res.size() > cap) res.resize(cap);\n    return res;\n}\n\nstruct PairSpec {\n    int A1, B1, A2, B2;\n};\n\nvector<PairSpec> generate_orth_specs() {\n    const double PI = acos(-1.0);\n    const int L = 997;\n    vector<PairSpec> res;\n    set<tuple<int,int,int,int>> used;\n\n    for (int i = 0; i < 30; i++) {\n        double ang = PI * i / 30.0;\n        int dx = (int)llround(L * cos(ang));\n        int dy = (int)llround(L * sin(ang));\n        tie(dx, dy) = normalize_vec(dx, dy);\n\n        auto [A1, B1] = normalize_vec(-dy, dx);\n        auto [A2, B2] = normalize_vec(dx, dy);\n\n        auto key = make_tuple(A1, B1, A2, B2);\n        if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n    }\n\n    vector<pair<int,int>> extra_dirs = {\n        {1,0},{0,1},{1,1},{2,1},{1,2},{3,1},{1,3},{3,2},{2,3},{4,1},{1,4}\n    };\n    for (auto [dx0, dy0] : extra_dirs) {\n        auto [dx, dy] = normalize_vec(dx0, dy0);\n        auto [A1, B1] = normalize_vec(-dy, dx);\n        auto [A2, B2] = normalize_vec(dx, dy);\n        auto key = make_tuple(A1, B1, A2, B2);\n        if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n    }\n\n    return res;\n}\n\ndouble line_dir_angle_from_normal(int A, int B) {\n    return atan2((double)-A, (double)B);\n}\n\nvector<PairSpec> generate_near_specs(const Sol& s) {\n    const double PI = acos(-1.0);\n    const int L = 2003;\n    set<tuple<int,int,int,int>> used;\n    vector<PairSpec> res;\n\n    double a1 = line_dir_angle_from_normal(s.A1, s.B1);\n    double a2 = line_dir_angle_from_normal(s.A2, s.B2);\n\n    vector<double> da_list = {-4,-2,-1,0,1,2,4};\n    vector<double> db_list = {-15,0,15};\n\n    for (double da_deg : da_list) {\n        for (double db_deg : db_list) {\n            double ang1 = a1 + da_deg * PI / 180.0;\n            double ang2 = a2 + da_deg * PI / 180.0 + db_deg * PI / 180.0;\n\n            int dx1 = (int)llround(L * cos(ang1));\n            int dy1 = (int)llround(L * sin(ang1));\n            int dx2 = (int)llround(L * cos(ang2));\n            int dy2 = (int)llround(L * sin(ang2));\n\n            tie(dx1, dy1) = normalize_vec(dx1, dy1);\n            tie(dx2, dy2) = normalize_vec(dx2, dy2);\n\n            auto [A1, B1] = normalize_vec(-dy1, dx1);\n            auto [A2, B2] = normalize_vec(-dy2, dx2);\n\n            long long det = 1LL * A1 * B2 - 1LL * B1 * A2;\n            if (det == 0) continue;\n\n            auto key = make_tuple(A1, B1, A2, B2);\n            if (used.insert(key).second) res.push_back({A1, B1, A2, B2});\n        }\n    }\n\n    auto key = make_tuple(s.A1, s.B1, s.A2, s.B2);\n    if (used.insert(key).second) res.push_back({s.A1, s.B1, s.A2, s.B2});\n\n    return res;\n}\n\nPairSpec random_near_spec(const Sol& s, mt19937& rng) {\n    const double PI = acos(-1.0);\n    const int L = 3001;\n    double a1 = line_dir_angle_from_normal(s.A1, s.B1);\n    double a2 = line_dir_angle_from_normal(s.A2, s.B2);\n\n    for (int rep = 0; rep < 20; rep++) {\n        double d1 = ((int)(rng() % 17) - 8) * (PI / 180.0) * 0.5;  // [-4,4] deg step 0.5\n        double d2 = ((int)(rng() % 41) - 20) * (PI / 180.0) * 0.5; // [-10,10]\n        double ang1 = a1 + d1;\n        double ang2 = a2 + d1 + d2;\n\n        int dx1 = (int)llround(L * cos(ang1));\n        int dy1 = (int)llround(L * sin(ang1));\n        int dx2 = (int)llround(L * cos(ang2));\n        int dy2 = (int)llround(L * sin(ang2));\n        tie(dx1, dy1) = normalize_vec(dx1, dy1);\n        tie(dx2, dy2) = normalize_vec(dx2, dy2);\n        auto [A1, B1] = normalize_vec(-dy1, dx1);\n        auto [A2, B2] = normalize_vec(-dy2, dx2);\n        long long det = 1LL * A1 * B2 - 1LL * B1 * A2;\n        if (det != 0) return {A1, B1, A2, B2};\n    }\n    return {s.A1, s.B1, s.A2, s.B2};\n}\n\nstruct PairData {\n    int A1, B1, A2, B2;\n    double len1, len2;\n    long long lim1, lim2;\n    vector<long long> v1, v2;\n    vector<int> ord1, ord2;\n    vector<long long> s1, s2;\n    vector<char> feas1, feas2;\n    vector<int> fp1, fp2;\n    unordered_set<long long> forb1, forb2;\n};\n\nPairData prepare_pair(const vector<Point>& pts, const PairSpec& sp) {\n    PairData D;\n    D.A1 = sp.A1; D.B1 = sp.B1;\n    D.A2 = sp.A2; D.B2 = sp.B2;\n    D.len1 = hypot((double)D.A1, (double)D.B1);\n    D.len2 = hypot((double)D.A2, (double)D.B2);\n    D.lim1 = (long long)floor(R * D.len1 - 1e-7);\n    D.lim2 = (long long)floor(R * D.len2 - 1e-7);\n\n    int N = (int)pts.size();\n    D.v1.resize(N);\n    D.v2.resize(N);\n    D.ord1.resize(N);\n    D.ord2.resize(N);\n    D.forb1.reserve(N * 2 + 10);\n    D.forb2.reserve(N * 2 + 10);\n\n    for (int i = 0; i < N; i++) {\n        long long p1 = 1LL * D.A1 * pts[i].x + 1LL * D.B1 * pts[i].y;\n        long long p2 = 1LL * D.A2 * pts[i].x + 1LL * D.B2 * pts[i].y;\n        D.v1[i] = p1;\n        D.v2[i] = p2;\n        D.ord1[i] = i;\n        D.ord2[i] = i;\n        D.forb1.insert(p1);\n        D.forb2.insert(p2);\n    }\n\n    sort(D.ord1.begin(), D.ord1.end(), [&](int i, int j) {\n        if (D.v1[i] != D.v1[j]) return D.v1[i] < D.v1[j];\n        return i < j;\n    });\n    sort(D.ord2.begin(), D.ord2.end(), [&](int i, int j) {\n        if (D.v2[i] != D.v2[j]) return D.v2[i] < D.v2[j];\n        return i < j;\n    });\n\n    D.s1.resize(N);\n    D.s2.resize(N);\n    for (int i = 0; i < N; i++) {\n        D.s1[i] = D.v1[D.ord1[i]];\n        D.s2[i] = D.v2[D.ord2[i]];\n    }\n\n    D.feas1.assign(N + 1, 0);\n    D.feas2.assign(N + 1, 0);\n    for (int p = 1; p < N; p++) {\n        if (D.s1[p] - D.s1[p - 1] >= 2) {\n            D.feas1[p] = 1;\n            D.fp1.push_back(p);\n        }\n        if (D.s2[p] - D.s2[p - 1] >= 2) {\n            D.feas2[p] = 1;\n            D.fp2.push_back(p);\n        }\n    }\n\n    return D;\n}\n\nlong long adjust_constant(\n    long long target,\n    long long low,\n    long long high,\n    const unordered_set<long long>& forbidden\n) {\n    for (long long d = 0;; d++) {\n        long long c1 = target - d;\n        if (c1 >= low && c1 <= high && !forbidden.count(c1)) return c1;\n        if (d == 0) continue;\n        long long c2 = target + d;\n        if (c2 >= low && c2 <= high && !forbidden.count(c2)) return c2;\n    }\n}\n\nvoid build_bins_from_cuts(\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const vector<long long>& cuts,\n    vector<int>& bin\n) {\n    int N = (int)sortedVals.size();\n    bin.assign(N, 0);\n    int cur = 0, M = (int)cuts.size();\n    for (int r = 0; r < N; r++) {\n        while (cur < M && sortedVals[r] > cuts[cur]) cur++;\n        bin[ord[r]] = cur;\n    }\n}\n\nPart build_width_part(\n    int m,\n    double frac,\n    double len,\n    long long lim,\n    const vector<long long>& sortedVals,\n    const vector<int>& ord,\n    const unordered_set<long long>& forbidden\n) {\n    Part part;\n    part.m = m;\n    int N = (int)sortedVals.size();\n\n    if (m == 1) {\n        part.bin.assign(N, 0);\n        return part;\n    }\n\n    double w = 2.0 * R / m;\n    vector<long long> cuts;\n    cuts.reserve(m - 1);\n\n    long long prev = -lim - 1;\n    for (int j = 0; j < m - 1; j++) {\n        double pos = -R + frac * w + j * w;\n        long long target = llround(pos * len);\n        long long c = adjust_constant(target, max(-lim + 1, prev + 1), lim - 1, forbidden);\n        cuts.push_back(c);\n        prev = c;\n    }\n\n    part.cuts = cuts;\n    build_bins_from_cuts(sortedVals, ord, cuts, part.bin);\n    return part;\n}\n\nbool same_sol(const Sol& a, const Sol& b) {\n    return a.A1 == b.A1 && a.B1 == b.B1 &&\n           a.A2 == b.A2 && a.B2 == b.B2 &&\n           a.m1 == b.m1 && a.m2 == b.m2 &&\n           a.cuts1 == b.cuts1 && a.cuts2 == b.cuts2;\n}\n\nvoid add_pool(vector<Sol>& pool, const Sol& cand, int limit) {\n    for (auto& x : pool) {\n        if (same_sol(x, cand)) {\n            if (better_sol(cand, x)) x = cand;\n            sort(pool.begin(), pool.end(), better_sol);\n            if ((int)pool.size() > limit) pool.resize(limit);\n            return;\n        }\n    }\n    pool.push_back(cand);\n    sort(pool.begin(), pool.end(), better_sol);\n    if ((int)pool.size() > limit) pool.resize(limit);\n}\n\nvoid try_eval_pair(\n    const Part& p1,\n    const Part& p2,\n    const PairSpec& sp,\n    const array<int,11>& a,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    static int cnt[105 * 105];\n    int cells = p1.m * p2.m;\n    for (int i = 0; i < cells; i++) cnt[i] = 0;\n\n    int N = (int)p1.bin.size();\n    for (int i = 0; i < N; i++) {\n        cnt[p1.bin[i] * p2.m + p2.bin[i]]++;\n    }\n\n    int hist[11] = {};\n    int good = 0;\n    for (int i = 0; i < cells; i++) {\n        int c = cnt[i];\n        if (1 <= c && c <= 10) {\n            hist[c]++;\n            good++;\n        }\n    }\n\n    int sc = 0;\n    for (int d = 1; d <= 10; d++) sc += min(a[d], hist[d]);\n\n    Sol cand;\n    cand.score = sc;\n    cand.goodCells = good;\n    cand.A1 = sp.A1; cand.B1 = sp.B1;\n    cand.A2 = sp.A2; cand.B2 = sp.B2;\n    cand.m1 = p1.m; cand.m2 = p2.m;\n    cand.cuts1 = p1.cuts;\n    cand.cuts2 = p2.cuts;\n\n    if (better_sol(cand, best)) best = cand;\n    if (pool) {\n        if ((int)pool->size() < poolLimit ||\n            better_pair(sc, good, pool->back().score, pool->back().goodCells)) {\n            add_pool(*pool, cand, poolLimit);\n        }\n    }\n}\n\nvoid search_with_specs(\n    const vector<Point>& pts,\n    const array<int,11>& a,\n    const vector<PairSpec>& specs,\n    const vector<pair<int,int>>& pairs,\n    const vector<double>& fracs,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    set<int> msset;\n    for (auto [m1, m2] : pairs) {\n        msset.insert(m1);\n        msset.insert(m2);\n    }\n    vector<int> ms(msset.begin(), msset.end());\n\n    for (const auto& sp : specs) {\n        PairData D = prepare_pair(pts, sp);\n        vector<vector<Part>> parts1(102), parts2(102);\n\n        for (int m : ms) {\n            if (m == 1) {\n                parts1[m].push_back(build_width_part(1, 0.5, D.len1, D.lim1, D.s1, D.ord1, D.forb1));\n                parts2[m].push_back(build_width_part(1, 0.5, D.len2, D.lim2, D.s2, D.ord2, D.forb2));\n            } else {\n                for (double f : fracs) {\n                    parts1[m].push_back(build_width_part(m, f, D.len1, D.lim1, D.s1, D.ord1, D.forb1));\n                    parts2[m].push_back(build_width_part(m, f, D.len2, D.lim2, D.s2, D.ord2, D.forb2));\n                }\n            }\n        }\n\n        for (auto [m1, m2] : pairs) {\n            for (const auto& p1 : parts1[m1]) {\n                for (const auto& p2 : parts2[m2]) {\n                    try_eval_pair(p1, p2, sp, a, best, pool, poolLimit);\n                }\n            }\n        }\n    }\n}\n\nstruct LocalOptimizer {\n    const PairData& D;\n    const array<int,11>& a;\n    int N, m1, m2;\n\n    vector<int> pos1, pos2;\n    vector<int> bin1, bin2;\n    vector<int> cnt;\n    int hist[11]{};\n    int score = 0;\n    int good = 0;\n\n    LocalOptimizer(const PairData& D_, const array<int,11>& a_, int m1_, int m2_)\n        : D(D_), a(a_), N((int)D_.s1.size()), m1(m1_), m2(m2_) {}\n\n    static vector<int> cuts_to_pos(const vector<long long>& sortedVals, const vector<long long>& cuts) {\n        vector<int> pos;\n        pos.reserve(cuts.size());\n        for (long long c : cuts) {\n            int p = upper_bound(sortedVals.begin(), sortedVals.end(), c) - sortedVals.begin();\n            pos.push_back(p);\n        }\n        return pos;\n    }\n\n    static bool strictly_increasing(const vector<int>& pos) {\n        for (int i = 1; i < (int)pos.size(); i++) if (pos[i] <= pos[i - 1]) return false;\n        return true;\n    }\n\n    static vector<long long> pos_to_cuts(const vector<long long>& sortedVals, const vector<int>& pos) {\n        vector<long long> cuts;\n        cuts.reserve(pos.size());\n        for (int p : pos) {\n            long long L = sortedVals[p - 1];\n            long long U = sortedVals[p];\n            long long c = (L + U) / 2;\n            if (c <= L) c = L + 1;\n            if (c >= U) c = U - 1;\n            cuts.push_back(c);\n        }\n        return cuts;\n    }\n\n    void build_bins_from_pos(const vector<int>& pos, const vector<int>& ord, vector<int>& bin) {\n        bin.assign(N, 0);\n        int cur = 0;\n        for (int r = 0; r < N; r++) {\n            while (cur < (int)pos.size() && r >= pos[cur]) cur++;\n            bin[ord[r]] = cur;\n        }\n    }\n\n    void rebuild_all() {\n        build_bins_from_pos(pos1, D.ord1, bin1);\n        build_bins_from_pos(pos2, D.ord2, bin2);\n\n        cnt.assign(m1 * m2, 0);\n        fill(hist, hist + 11, 0);\n        score = 0;\n        good = 0;\n\n        for (int i = 0; i < N; i++) {\n            cnt[bin1[i] * m2 + bin2[i]]++;\n        }\n        for (int v : cnt) {\n            if (1 <= v && v <= 10) {\n                hist[v]++;\n                good++;\n            }\n        }\n        for (int d = 1; d <= 10; d++) score += min(a[d], hist[d]);\n    }\n\n    bool valid_pos_family(const vector<int>& pos, const vector<char>& feas) const {\n        if (!strictly_increasing(pos)) return false;\n        for (int p : pos) {\n            if (!(1 <= p && p < N && feas[p])) return false;\n        }\n        return true;\n    }\n\n    bool init_from_positions(const vector<int>& p1, const vector<int>& p2) {\n        pos1 = p1;\n        pos2 = p2;\n        if (!valid_pos_family(pos1, D.feas1)) return false;\n        if (!valid_pos_family(pos2, D.feas2)) return false;\n        rebuild_all();\n        return true;\n    }\n\n    bool init_from_cuts(const vector<long long>& cuts1, const vector<long long>& cuts2) {\n        return init_from_positions(cuts_to_pos(D.s1, cuts1), cuts_to_pos(D.s2, cuts2));\n    }\n\n    inline void remove_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] - 1) - min(a[v], hist[v]);\n            hist[v]--;\n            good--;\n        }\n    }\n    inline void add_hist(int v) {\n        if (1 <= v && v <= 10) {\n            score += min(a[v], hist[v] + 1) - min(a[v], hist[v]);\n            hist[v]++;\n            good++;\n        }\n    }\n    inline void modify_cell(int idx, int delta) {\n        int oldv = cnt[idx];\n        int newv = oldv + delta;\n        remove_hist(oldv);\n        cnt[idx] = newv;\n        add_hist(newv);\n    }\n\n    bool optimize_cut1(int j) {\n        int old = pos1[j];\n        int prv = (j == 0 ? 0 : pos1[j - 1]);\n        int nxt = (j + 1 == (int)pos1.size() ? N : pos1[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n            int p = r + 1;\n            if (p < nxt && D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell(j * m2 + b, -1);\n            modify_cell((j + 1) * m2 + b, +1);\n            int p = r;\n            if (D.feas1[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord1[r];\n            int b = bin2[id];\n            modify_cell((j + 1) * m2 + b, -1);\n            modify_cell(j * m2 + b, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell((j + 1) * m2 + b, -1);\n                modify_cell(j * m2 + b, +1);\n                bin1[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord1[r];\n                int b = bin2[id];\n                modify_cell(j * m2 + b, -1);\n                modify_cell((j + 1) * m2 + b, +1);\n                bin1[id]++;\n            }\n        }\n        pos1[j] = bestp;\n        return true;\n    }\n\n    bool optimize_cut2(int j) {\n        int old = pos2[j];\n        int prv = (j == 0 ? 0 : pos2[j - 1]);\n        int nxt = (j + 1 == (int)pos2.size() ? N : pos2[j + 1]);\n\n        int bestp = old;\n        int bestSc = score, bestGood = good;\n\n        for (int r = old; r < nxt; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n            int p = r + 1;\n            if (p < nxt && D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = nxt - 1; r >= old; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n        }\n\n        for (int r = old - 1; r >= prv + 1; r--) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + j, -1);\n            modify_cell(b * m2 + (j + 1), +1);\n            int p = r;\n            if (D.feas2[p]) {\n                if (better_pair(score, good, bestSc, bestGood)) {\n                    bestSc = score; bestGood = good; bestp = p;\n                }\n            }\n        }\n        for (int r = prv + 1; r <= old - 1; r++) {\n            int id = D.ord2[r];\n            int b = bin1[id];\n            modify_cell(b * m2 + (j + 1), -1);\n            modify_cell(b * m2 + j, +1);\n        }\n\n        if (bestp == old) return false;\n\n        if (bestp > old) {\n            for (int r = old; r < bestp; r++) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + (j + 1), -1);\n                modify_cell(b * m2 + j, +1);\n                bin2[id]--;\n            }\n        } else {\n            for (int r = old - 1; r >= bestp; r--) {\n                int id = D.ord2[r];\n                int b = bin1[id];\n                modify_cell(b * m2 + j, -1);\n                modify_cell(b * m2 + (j + 1), +1);\n                bin2[id]++;\n            }\n        }\n        pos2[j] = bestp;\n        return true;\n    }\n\n    void optimize(int rounds = 10) {\n        for (int it = 0; it < rounds; it++) {\n            bool changed = false;\n            if (it % 2 == 0) {\n                for (int j = 0; j < (int)pos1.size(); j++) changed |= optimize_cut1(j);\n                for (int j = 0; j < (int)pos2.size(); j++) changed |= optimize_cut2(j);\n            } else {\n                for (int j = (int)pos2.size() - 1; j >= 0; j--) changed |= optimize_cut2(j);\n                for (int j = (int)pos1.size() - 1; j >= 0; j--) changed |= optimize_cut1(j);\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<long long> final_cuts1() const { return pos_to_cuts(D.s1, pos1); }\n    vector<long long> final_cuts2() const { return pos_to_cuts(D.s2, pos2); }\n};\n\nvector<Sol> pick_unique_geom_seeds(const vector<Sol>& pool, int limit) {\n    vector<Sol> res;\n    set<tuple<int,int,int,int,int,int>> used;\n    for (const auto& s : pool) {\n        auto key = make_tuple(s.A1, s.B1, s.A2, s.B2, s.m1, s.m2);\n        if (used.insert(key).second) {\n            res.push_back(s);\n            if ((int)res.size() >= limit) break;\n        }\n    }\n    return res;\n}\n\nvector<Sol> pick_top_exact(const vector<Sol>& pool, int limit) {\n    vector<Sol> res;\n    for (int i = 0; i < (int)pool.size() && i < limit; i++) res.push_back(pool[i]);\n    return res;\n}\n\nvector<Sol> merge_seed_lists(const vector<Sol>& A, const vector<Sol>& B, int limit) {\n    vector<Sol> res;\n    for (auto &s : A) add_pool(res, s, limit);\n    for (auto &s : B) add_pool(res, s, limit);\n    return res;\n}\n\nvector<int> build_quantile_pos_from_list(const vector<int>& fp, int N, int m) {\n    vector<int> pos;\n    if (m <= 1) return pos;\n    if ((int)fp.size() < m - 1) return {};\n\n    int leftIdx = 0;\n    for (int j = 1; j <= m - 1; j++) {\n        int remain = (m - 1) - j;\n        int lo = leftIdx;\n        int hi = (int)fp.size() - 1 - remain;\n        if (lo > hi) return {};\n\n        int target = (int)llround((long double)j * N / m);\n        int bestIndex = lo;\n        int bestDist = abs(fp[lo] - target);\n\n        auto it = lower_bound(fp.begin() + lo, fp.begin() + hi + 1, target);\n        if (it != fp.begin() + hi + 1) {\n            int idx = (int)(it - fp.begin());\n            int dist = abs(fp[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n        if (it != fp.begin() + lo) {\n            int idx = (int)((it - fp.begin()) - 1);\n            int dist = abs(fp[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n\n        pos.push_back(fp[bestIndex]);\n        leftIdx = bestIndex + 1;\n    }\n    return pos;\n}\n\nint nearest_feasible_in_range(const vector<int>& fp, int l, int r, int target) {\n    auto itL = lower_bound(fp.begin(), fp.end(), l);\n    auto itR = upper_bound(fp.begin(), fp.end(), r);\n    if (itL == itR) return -1;\n\n    auto it = lower_bound(itL, itR, target);\n    int best = -1, bestDist = INT_MAX;\n    if (it != itR) {\n        int p = *it;\n        int dist = abs(p - target);\n        if (dist < bestDist) bestDist = dist, best = p;\n    }\n    if (it != itL) {\n        --it;\n        int p = *it;\n        int dist = abs(p - target);\n        if (dist < bestDist) bestDist = dist, best = p;\n    }\n    return best;\n}\n\nvector<int> build_noisy_quantile_pos(const vector<int>& fp, int N, int m, mt19937& rng) {\n    vector<int> pos;\n    if (m <= 1) return pos;\n    if ((int)fp.size() < m - 1) return {};\n\n    int leftIdx = 0;\n    int noise = max(2, N / max(8 * m, 2));\n\n    for (int j = 1; j <= m - 1; j++) {\n        int remain = (m - 1) - j;\n        int lo = leftIdx;\n        int hi = (int)fp.size() - 1 - remain;\n        if (lo > hi) return {};\n\n        int base = (int)llround((long double)j * N / m);\n        int target = base + (int)(rng() % (2 * noise + 1)) - noise;\n        target = max(1, min(N - 1, target));\n\n        auto it = lower_bound(fp.begin() + lo, fp.begin() + hi + 1, target);\n        int bestIndex = lo;\n        int bestDist = abs(fp[lo] - target);\n        if (it != fp.begin() + hi + 1) {\n            int idx = (int)(it - fp.begin());\n            int dist = abs(fp[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n        if (it != fp.begin() + lo) {\n            int idx = (int)((it - fp.begin()) - 1);\n            int dist = abs(fp[idx] - target);\n            if (dist < bestDist) bestDist = dist, bestIndex = idx;\n        }\n\n        pos.push_back(fp[bestIndex]);\n        leftIdx = bestIndex + 1;\n    }\n    return pos;\n}\n\nvector<int> jitter_positions(const vector<int>& base, const vector<int>& fp, int N, mt19937& rng) {\n    vector<int> np = base;\n    if (np.empty()) return np;\n    int moves = 1 + (int)(rng() % min(3, (int)np.size()));\n    int span = max(3, N / max(6 * ((int)np.size() + 1), 2));\n\n    for (int it = 0; it < moves; it++) {\n        int j = (int)(rng() % np.size());\n        int l = (j == 0 ? 1 : np[j - 1] + 1);\n        int r = (j + 1 == (int)np.size() ? N - 1 : np[j + 1] - 1);\n        if (l > r) continue;\n\n        int target = np[j] + (int)(rng() % (2 * span + 1)) - span;\n        target = max(l, min(r, target));\n        int p = nearest_feasible_in_range(fp, l, r, target);\n        if (p != -1) np[j] = p;\n    }\n    return np;\n}\n\nvector<vector<int>> generate_add_cut_candidates(const vector<int>& pos, const vector<char>& feas, int N, int maxCand = 2) {\n    vector<int> b;\n    b.reserve(pos.size() + 2);\n    b.push_back(0);\n    for (int p : pos) b.push_back(p);\n    b.push_back(N);\n\n    vector<pair<int, vector<int>>> cands;\n    for (int t = 0; t + 1 < (int)b.size(); t++) {\n        int l = b[t], r = b[t + 1];\n        if (r - l <= 1) continue;\n\n        int mid = (l + r) / 2;\n        int bestp = -1, bestDist = INT_MAX;\n        for (int p = max(l + 1, 1); p <= min(r - 1, N - 1); p++) {\n            if (!feas[p]) continue;\n            int dist = abs(p - mid);\n            if (dist < bestDist) {\n                bestDist = dist;\n                bestp = p;\n            }\n        }\n        if (bestp == -1) continue;\n\n        vector<int> np = pos;\n        np.insert(np.begin() + t, bestp);\n        cands.push_back({r - l, np});\n    }\n\n    sort(cands.begin(), cands.end(), [&](auto& L, auto& Rr) {\n        return L.first > Rr.first;\n    });\n\n    vector<vector<int>> res;\n    for (int i = 0; i < (int)cands.size() && i < maxCand; i++) res.push_back(cands[i].second);\n    return res;\n}\n\nvector<vector<int>> generate_remove_cut_candidates(const vector<int>& pos, int N, int maxCand = 2) {\n    vector<int> b;\n    b.reserve(pos.size() + 2);\n    b.push_back(0);\n    for (int p : pos) b.push_back(p);\n    b.push_back(N);\n\n    vector<pair<int, vector<int>>> cands;\n    for (int j = 0; j < (int)pos.size(); j++) {\n        int merged = b[j + 2] - b[j];\n        vector<int> np = pos;\n        np.erase(np.begin() + j);\n        cands.push_back({merged, np});\n    }\n\n    sort(cands.begin(), cands.end(), [&](auto& L, auto& Rr) {\n        return L.first < Rr.first;\n    });\n\n    vector<vector<int>> res;\n    for (int i = 0; i < (int)cands.size() && i < maxCand; i++) res.push_back(cands[i].second);\n    return res;\n}\n\nbool try_local_from_positions(\n    const PairData& D, const array<int,11>& a,\n    int m1, int m2,\n    const vector<int>& pos1, const vector<int>& pos2,\n    int rounds,\n    Sol& best,\n    vector<Sol>* pool = nullptr,\n    int poolLimit = 0\n) {\n    LocalOptimizer opt(D, a, m1, m2);\n    if (!opt.init_from_positions(pos1, pos2)) return false;\n    opt.optimize(rounds);\n\n    Sol cand;\n    cand.score = opt.score;\n    cand.goodCells = opt.good;\n    cand.A1 = D.A1; cand.B1 = D.B1;\n    cand.A2 = D.A2; cand.B2 = D.B2;\n    cand.m1 = m1; cand.m2 = m2;\n    cand.cuts1 = opt.final_cuts1();\n    cand.cuts2 = opt.final_cuts2();\n\n    if (better_sol(cand, best)) best = cand;\n    if (pool) add_pool(*pool, cand, poolLimit);\n    return true;\n}\n\nbool final_refine_best(const vector<Point>& pts, const array<int,11>& a, Sol& best, int rounds) {\n    PairSpec sp{best.A1, best.B1, best.A2, best.B2};\n    PairData D = prepare_pair(pts, sp);\n    LocalOptimizer opt(D, a, best.m1, best.m2);\n    if (!opt.init_from_cuts(best.cuts1, best.cuts2)) return false;\n    opt.optimize(rounds);\n    Sol cand = best;\n    cand.score = opt.score;\n    cand.goodCells = opt.good;\n    cand.cuts1 = opt.final_cuts1();\n    cand.cuts2 = opt.final_cuts2();\n    if (better_sol(cand, best)) best = cand;\n    return true;\n}\n\nvector<Sol> build_dynamic_seeds(const vector<Sol>& pool, const Sol& best, int limit) {\n    auto top = pick_top_exact(pool, min(limit, 8));\n    auto uniq = pick_unique_geom_seeds(pool, min(limit, 8));\n    auto res = merge_seed_lists(top, uniq, limit);\n    add_pool(res, best, limit);\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto time_begin = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - time_begin).count();\n    };\n\n    int N, K;\n    cin >> N >> K;\n\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 A = 0;\n    for (int d = 1; d <= 10; d++) A += a[d];\n\n    Sol best;\n    vector<Sol> pool;\n\n    // 1) Coarse orthogonal search\n    auto coarseSpecs = generate_orth_specs();\n    auto coarsePairs = generate_pairs(N, A, a, 84);\n    vector<double> coarseFracs = {0.25, 0.5, 0.75};\n    search_with_specs(pts, a, coarseSpecs, coarsePairs, coarseFracs, best, &pool, 30);\n\n    // 2) Refine around several seeds, including slight skewness\n    {\n        auto seeds = pick_unique_geom_seeds(pool, 5);\n        vector<double> fineFracs = {0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875};\n\n        for (const auto& sd : seeds) {\n            auto nearSpecs = generate_near_specs(sd);\n            vector<pair<int,int>> nearPairs;\n            for (int m1 = max(1, sd.m1 - 2); m1 <= min(101, sd.m1 + 2); m1++) {\n                for (int m2 = max(1, sd.m2 - 2); m2 <= min(101, sd.m2 + 2); m2++) {\n                    if (m1 + m2 - 2 <= MAXK) nearPairs.push_back({m1, m2});\n                }\n            }\n            search_with_specs(pts, a, nearSpecs, nearPairs, fineFracs, best, &pool, 42);\n        }\n    }\n\n    // 3) Local optimization on many seeds\n    {\n        auto topSeeds = pick_top_exact(pool, 14);\n        auto uniqSeeds = pick_unique_geom_seeds(pool, 12);\n        auto localSeeds = merge_seed_lists(topSeeds, uniqSeeds, 22);\n\n        for (const auto& sd : localSeeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n            LocalOptimizer opt(D, a, sd.m1, sd.m2);\n            if (!opt.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n            opt.optimize(10);\n\n            Sol cand = sd;\n            cand.score = opt.score;\n            cand.goodCells = opt.good;\n            cand.cuts1 = opt.final_cuts1();\n            cand.cuts2 = opt.final_cuts2();\n\n            if (better_sol(cand, best)) best = cand;\n            add_pool(pool, cand, 42);\n        }\n    }\n\n    // 4) Quantile-based alternative seeds\n    {\n        auto seeds = pick_unique_geom_seeds(pool, 6);\n        for (const auto& sd : seeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n\n            vector<int> q1 = build_quantile_pos_from_list(D.fp1, N, sd.m1);\n            vector<int> q2 = build_quantile_pos_from_list(D.fp2, N, sd.m2);\n\n            if ((!q1.empty() || sd.m1 == 1) && (!q2.empty() || sd.m2 == 1)) {\n                try_local_from_positions(D, a, sd.m1, sd.m2, q1, q2, 10, best, &pool, 42);\n            }\n\n            LocalOptimizer tmp(D, a, sd.m1, sd.m2);\n            if (tmp.init_from_cuts(sd.cuts1, sd.cuts2)) {\n                if (!q1.empty() || sd.m1 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, q1, tmp.pos2, 8, best, &pool, 42);\n                }\n                if (!q2.empty() || sd.m2 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, tmp.pos1, q2, 8, best, &pool, 42);\n                }\n            }\n        }\n    }\n\n    // 5) Structural neighborhood\n    {\n        auto topSeeds = pick_top_exact(pool, 8);\n        auto uniqSeeds = pick_unique_geom_seeds(pool, 8);\n        auto structSeeds = merge_seed_lists(topSeeds, uniqSeeds, 10);\n\n        for (const auto& sd : structSeeds) {\n            PairSpec sp{sd.A1, sd.B1, sd.A2, sd.B2};\n            PairData D = prepare_pair(pts, sp);\n            LocalOptimizer base(D, a, sd.m1, sd.m2);\n            if (!base.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n\n            if (sd.m1 + sd.m2 - 1 <= MAXK) {\n                auto cands = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                for (auto& np1 : cands) {\n                    try_local_from_positions(D, a, sd.m1 + 1, sd.m2, np1, base.pos2, 8, best, &pool, 42);\n                }\n            }\n            if (sd.m1 >= 2) {\n                auto cands = generate_remove_cut_candidates(base.pos1, N, 2);\n                for (auto& np1 : cands) {\n                    try_local_from_positions(D, a, sd.m1 - 1, sd.m2, np1, base.pos2, 8, best, &pool, 42);\n                }\n            }\n            if (sd.m1 + sd.m2 - 1 <= MAXK) {\n                auto cands = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                for (auto& np2 : cands) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2 + 1, base.pos1, np2, 8, best, &pool, 42);\n                }\n            }\n            if (sd.m2 >= 2) {\n                auto cands = generate_remove_cut_candidates(base.pos2, N, 2);\n                for (auto& np2 : cands) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2 - 1, base.pos1, np2, 8, best, &pool, 42);\n                }\n            }\n\n            if (sd.m2 >= 2) {\n                auto add1 = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                auto rem2 = generate_remove_cut_candidates(base.pos2, N, 2);\n                for (auto& np1 : add1) for (auto& np2 : rem2) {\n                    try_local_from_positions(D, a, sd.m1 + 1, sd.m2 - 1, np1, np2, 8, best, &pool, 42);\n                }\n            }\n            if (sd.m1 >= 2) {\n                auto rem1 = generate_remove_cut_candidates(base.pos1, N, 2);\n                auto add2 = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                for (auto& np1 : rem1) for (auto& np2 : add2) {\n                    try_local_from_positions(D, a, sd.m1 - 1, sd.m2 + 1, np1, np2, 8, best, &pool, 42);\n                }\n            }\n        }\n    }\n\n    // 6) Dynamic randomized perturbation\n    {\n        mt19937 rng((unsigned)N * 1000003u + (unsigned)A * 911382323u + 1234567u);\n        vector<Sol> randSeeds;\n        vector<PairData> randData;\n        int iter = 0;\n\n        auto refresh_rand = [&]() {\n            randSeeds = build_dynamic_seeds(pool, best, 10);\n            randData.clear();\n            randData.reserve(randSeeds.size());\n            for (auto& sd : randSeeds) {\n                randData.push_back(prepare_pair(pts, PairSpec{sd.A1, sd.B1, sd.A2, sd.B2}));\n            }\n        };\n\n        refresh_rand();\n        while (elapsed_ms() < 2820.0 && !randSeeds.empty()) {\n            if ((iter & 15) == 0) refresh_rand();\n            iter++;\n\n            int lim = min<int>((int)randSeeds.size(), 6);\n            int pick = (int)(rng() % (lim * lim));\n            int idx = min(lim - 1, (int)sqrt((double)pick));\n            const auto& sd = randSeeds[idx];\n            const auto& D = randData[idx];\n\n            LocalOptimizer base(D, a, sd.m1, sd.m2);\n            if (!base.init_from_cuts(sd.cuts1, sd.cuts2)) continue;\n\n            int mode = (int)(rng() % 10);\n\n            if (mode == 0) {\n                auto np1 = jitter_positions(base.pos1, D.fp1, N, rng);\n                try_local_from_positions(D, a, sd.m1, sd.m2, np1, base.pos2, 6, best, &pool, 60);\n            } else if (mode == 1) {\n                auto np2 = jitter_positions(base.pos2, D.fp2, N, rng);\n                try_local_from_positions(D, a, sd.m1, sd.m2, base.pos1, np2, 6, best, &pool, 60);\n            } else if (mode == 2) {\n                auto np1 = build_noisy_quantile_pos(D.fp1, N, sd.m1, rng);\n                if (!np1.empty() || sd.m1 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, np1, base.pos2, 6, best, &pool, 60);\n                }\n            } else if (mode == 3) {\n                auto np2 = build_noisy_quantile_pos(D.fp2, N, sd.m2, rng);\n                if (!np2.empty() || sd.m2 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, base.pos1, np2, 6, best, &pool, 60);\n                }\n            } else if (mode == 4) {\n                auto np1 = build_noisy_quantile_pos(D.fp1, N, sd.m1, rng);\n                auto np2 = build_noisy_quantile_pos(D.fp2, N, sd.m2, rng);\n                if ((!np1.empty() || sd.m1 == 1) && (!np2.empty() || sd.m2 == 1)) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, np1, np2, 6, best, &pool, 60);\n                }\n            } else if (mode == 5 && sd.m2 >= 2) {\n                auto add1 = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                auto rem2 = generate_remove_cut_candidates(base.pos2, N, 2);\n                if (!add1.empty() && !rem2.empty()) {\n                    auto& np1 = add1[rng() % add1.size()];\n                    auto& np2 = rem2[rng() % rem2.size()];\n                    try_local_from_positions(D, a, sd.m1 + 1, sd.m2 - 1, np1, np2, 6, best, &pool, 60);\n                }\n            } else if (mode == 6 && sd.m1 >= 2) {\n                auto rem1 = generate_remove_cut_candidates(base.pos1, N, 2);\n                auto add2 = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                if (!rem1.empty() && !add2.empty()) {\n                    auto& np1 = rem1[rng() % rem1.size()];\n                    auto& np2 = add2[rng() % add2.size()];\n                    try_local_from_positions(D, a, sd.m1 - 1, sd.m2 + 1, np1, np2, 6, best, &pool, 60);\n                }\n            } else if (mode == 7) {\n                auto np1 = jitter_positions(base.pos1, D.fp1, N, rng);\n                auto np2 = jitter_positions(base.pos2, D.fp2, N, rng);\n                try_local_from_positions(D, a, sd.m1, sd.m2, np1, np2, 6, best, &pool, 60);\n            } else if (mode == 8) {\n                PairSpec rsp = random_near_spec(sd, rng);\n                PairData DD = prepare_pair(pts, rsp);\n                auto np1 = build_noisy_quantile_pos(DD.fp1, N, sd.m1, rng);\n                auto np2 = build_noisy_quantile_pos(DD.fp2, N, sd.m2, rng);\n                if ((!np1.empty() || sd.m1 == 1) && (!np2.empty() || sd.m2 == 1)) {\n                    try_local_from_positions(DD, a, sd.m1, sd.m2, np1, np2, 5, best, &pool, 60);\n                }\n            } else {\n                auto np1 = jitter_positions(base.pos1, D.fp1, N, rng);\n                auto np2 = build_noisy_quantile_pos(D.fp2, N, sd.m2, rng);\n                if (!np2.empty() || sd.m2 == 1) {\n                    try_local_from_positions(D, a, sd.m1, sd.m2, np1, np2, 6, best, &pool, 60);\n                }\n            }\n        }\n    }\n\n    // 7) Intensification around current best\n    {\n        mt19937 rng((unsigned)best.score * 2654435761u + 998244353u);\n        while (elapsed_ms() < 2940.0) {\n            PairSpec sp{best.A1, best.B1, best.A2, best.B2};\n            PairData D = prepare_pair(pts, sp);\n            LocalOptimizer base(D, a, best.m1, best.m2);\n            if (!base.init_from_cuts(best.cuts1, best.cuts2)) break;\n\n            int mode = (int)(rng() % 6);\n            if (mode == 0) {\n                auto np1 = jitter_positions(base.pos1, D.fp1, N, rng);\n                auto np2 = jitter_positions(base.pos2, D.fp2, N, rng);\n                try_local_from_positions(D, a, best.m1, best.m2, np1, np2, 7, best, nullptr, 0);\n            } else if (mode == 1) {\n                auto np1 = build_noisy_quantile_pos(D.fp1, N, best.m1, rng);\n                auto np2 = build_noisy_quantile_pos(D.fp2, N, best.m2, rng);\n                if ((!np1.empty() || best.m1 == 1) && (!np2.empty() || best.m2 == 1)) {\n                    try_local_from_positions(D, a, best.m1, best.m2, np1, np2, 7, best, nullptr, 0);\n                }\n            } else if (mode == 2) {\n                auto np1 = jitter_positions(base.pos1, D.fp1, N, rng);\n                try_local_from_positions(D, a, best.m1, best.m2, np1, base.pos2, 7, best, nullptr, 0);\n            } else if (mode == 3) {\n                auto np2 = jitter_positions(base.pos2, D.fp2, N, rng);\n                try_local_from_positions(D, a, best.m1, best.m2, base.pos1, np2, 7, best, nullptr, 0);\n            } else if (mode == 4) {\n                PairSpec rsp = random_near_spec(best, rng);\n                PairData DD = prepare_pair(pts, rsp);\n                auto np1 = build_noisy_quantile_pos(DD.fp1, N, best.m1, rng);\n                auto np2 = build_noisy_quantile_pos(DD.fp2, N, best.m2, rng);\n                if ((!np1.empty() || best.m1 == 1) && (!np2.empty() || best.m2 == 1)) {\n                    try_local_from_positions(DD, a, best.m1, best.m2, np1, np2, 5, best, nullptr, 0);\n                }\n            } else {\n                if (best.m2 >= 2) {\n                    auto add1 = generate_add_cut_candidates(base.pos1, D.feas1, N, 2);\n                    auto rem2 = generate_remove_cut_candidates(base.pos2, N, 2);\n                    if (!add1.empty() && !rem2.empty()) {\n                        auto& np1 = add1[rng() % add1.size()];\n                        auto& np2 = rem2[rng() % rem2.size()];\n                        try_local_from_positions(D, a, best.m1 + 1, best.m2 - 1, np1, np2, 6, best, nullptr, 0);\n                    }\n                } else if (best.m1 >= 2) {\n                    auto rem1 = generate_remove_cut_candidates(base.pos1, N, 2);\n                    auto add2 = generate_add_cut_candidates(base.pos2, D.feas2, N, 2);\n                    if (!rem1.empty() && !add2.empty()) {\n                        auto& np1 = rem1[rng() % rem1.size()];\n                        auto& np2 = add2[rng() % add2.size()];\n                        try_local_from_positions(D, a, best.m1 - 1, best.m2 + 1, np1, np2, 6, best, nullptr, 0);\n                    }\n                }\n            }\n        }\n    }\n\n    // 8) Final refine\n    final_refine_best(pts, a, best, 14);\n\n    vector<array<long long,4>> out;\n    out.reserve(best.cuts1.size() + best.cuts2.size());\n\n    for (long long c : best.cuts1) out.push_back(line_from_ABC(best.A1, best.B1, c));\n    for (long long c : best.cuts2) out.push_back(line_from_ABC(best.A2, best.B2, c));\n\n    if ((int)out.size() > K) out.resize(K);\n\n    cout << out.size() << '\\n';\n    for (auto &ln : out) {\n        cout << ln[0] << ' ' << ln[1] << ' ' << ln[2] << ' ' << ln[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int INF_PERIM = 1e9;\n\nusing Op = array<int, 8>;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : 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    double next_double() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\nstruct Cand {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n    int gain;\n    int perim;\n    int area;\n    int longSide;\n    double eval;\n};\n\nstruct EvalParams {\n    double beta;\n    double gamma;\n    double adjBonus;\n    double pairBonus;\n    double longPenalty;\n    int topKeep;\n    int pickTop;\n    double bias;\n    int maxPerim;\n};\n\nstruct Strategy {\n    vector<int> caps;\n    double betaHi, betaLo;\n    double gammaHi, gammaLo;\n    double adjHi, adjLo;\n    double pairHi, pairLo;\n    double longHi, longLo;\n    int topKeep;\n    int pickTop;\n    double bias;\n    bool quotaMode;\n    int stageLen;\n};\n\nstruct State {\n    int N = 0;\n    int dotCount = 0;\n    uint8_t dot[MAXN][MAXN]{};\n    uint8_t H[MAXN][MAXN]{};\n    uint8_t V[MAXN][MAXN]{};\n    uint8_t D1[MAXN][MAXN]{};\n    uint8_t D2[MAXN][MAXN]{};\n    long long sumW = 0;\n    vector<Op> ops;\n};\n\nint N, M;\nint W[MAXN][MAXN];\nvector<int> cellOrder;\n\nint eastA[MAXN][MAXN], westA[MAXN][MAXN], northA[MAXN][MAXN], southA[MAXN][MAXN];\nint neA[MAXN][MAXN], nwA[MAXN][MAXN], seA[MAXN][MAXN], swA[MAXN][MAXN];\n\ninline int enc(int x, int y) { return (x << 6) | y; }\ninline int decx(int v) { return v >> 6; }\ninline int decy(int v) { return v & 63; }\ninline bool inside(int x, int y) { return 0 <= x && x < N && 0 <= y && y < N; }\ninline int sgn(int x) { return (x > 0) - (x < 0); }\n\ninline bool segment_used(const State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) return st.H[min(x1, x2)][y1];\n    if (x1 == x2) return st.V[x1][min(y1, y2)];\n    if ((x2 - x1) == (y2 - y1)) return st.D1[min(x1, x2)][min(y1, y2)];\n    return st.D2[min(x1, x2)][min(y1, y2)];\n}\n\ninline void mark_segment(State& st, int x1, int y1, int x2, int y2) {\n    if (y1 == y2) {\n        st.H[min(x1, x2)][y1] = 1;\n    } else if (x1 == x2) {\n        st.V[x1][min(y1, y2)] = 1;\n    } else if ((x2 - x1) == (y2 - y1)) {\n        st.D1[min(x1, x2)][min(y1, y2)] = 1;\n    } else {\n        st.D2[min(x1, x2)][min(y1, y2)] = 1;\n    }\n}\n\ninline bool check_edge(const State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    if (len <= 0) return false;\n\n    int x = x1, y = y1;\n    for (int i = 1; i < len; i++) {\n        x += dx;\n        y += dy;\n        if (st.dot[x][y]) return false;\n    }\n\n    x = x1; y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        if (segment_used(st, x, y, nx, ny)) return false;\n        x = nx;\n        y = ny;\n    }\n    return true;\n}\n\ninline void mark_edge(State& st, int x1, int y1, int x2, int y2) {\n    int dx = sgn(x2 - x1);\n    int dy = sgn(y2 - y1);\n    int len = max(abs(x2 - x1), abs(y2 - y1));\n    int x = x1, y = y1;\n    for (int i = 0; i < len; i++) {\n        int nx = x + dx, ny = y + dy;\n        mark_segment(st, x, y, nx, ny);\n        x = nx;\n        y = ny;\n    }\n}\n\ninline bool valid_rect(const State& st, const Cand& c) {\n    if (st.dot[c.x1][c.y1]) return false;\n    if (!st.dot[c.x2][c.y2] || !st.dot[c.x3][c.y3] || !st.dot[c.x4][c.y4]) return false;\n    if (!check_edge(st, c.x1, c.y1, c.x2, c.y2)) return false;\n    if (!check_edge(st, c.x2, c.y2, c.x3, c.y3)) return false;\n    if (!check_edge(st, c.x3, c.y3, c.x4, c.y4)) return false;\n    if (!check_edge(st, c.x4, c.y4, c.x1, c.y1)) return false;\n    return true;\n}\n\ninline void apply_move(State& st, const Cand& c) {\n    st.dot[c.x1][c.y1] = 1;\n    st.dotCount++;\n    st.sumW += W[c.x1][c.y1];\n\n    mark_edge(st, c.x1, c.y1, c.x2, c.y2);\n    mark_edge(st, c.x2, c.y2, c.x3, c.y3);\n    mark_edge(st, c.x3, c.y3, c.x4, c.y4);\n    mark_edge(st, c.x4, c.y4, c.x1, c.y1);\n\n    st.ops.push_back({c.x1, c.y1, c.x2, c.y2, c.x3, c.y3, c.x4, c.y4});\n}\n\ninline void push_top(vector<Cand>& best, const Cand& c, int K) {\n    if ((int)best.size() < K) {\n        best.push_back(c);\n        int i = (int)best.size() - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    } else if (c.eval > best.back().eval) {\n        best.back() = c;\n        int i = K - 1;\n        while (i > 0 && best[i].eval > best[i - 1].eval) {\n            swap(best[i], best[i - 1]);\n            --i;\n        }\n    }\n}\n\ninline int adjacent_count8(const State& st, int x, int y) {\n    int cnt = 0;\n    for (int dx = -1; dx <= 1; dx++) {\n        int nx = x + dx;\n        if (nx < 0 || nx >= N) continue;\n        for (int dy = -1; dy <= 1; dy++) {\n            int ny = y + dy;\n            if (dx == 0 && dy == 0) continue;\n            if (ny < 0 || ny >= N) continue;\n            cnt += st.dot[nx][ny];\n        }\n    }\n    return cnt;\n}\n\nvoid build_nearest(const State& st) {\n    for (int y = 0; y < N; y++) {\n        int last = -1;\n        for (int x = 0; x < N; x++) {\n            westA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int x = N - 1; x >= 0; x--) {\n            eastA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        int last = -1;\n        for (int y = 0; y < N; y++) {\n            southA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n        last = -1;\n        for (int y = N - 1; y >= 0; y--) {\n            northA[x][y] = last;\n            if (st.dot[x][y]) last = enc(x, y);\n        }\n    }\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            swA[x][y] = (x == 0 || y == 0) ? -1\n                : (st.dot[x - 1][y - 1] ? enc(x - 1, y - 1) : swA[x - 1][y - 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = N - 1; y >= 0; y--) {\n            neA[x][y] = (x == N - 1 || y == N - 1) ? -1\n                : (st.dot[x + 1][y + 1] ? enc(x + 1, y + 1) : neA[x + 1][y + 1]);\n        }\n    }\n    for (int x = 0; x < N; x++) {\n        for (int y = N - 1; y >= 0; y--) {\n            nwA[x][y] = (x == 0 || y == N - 1) ? -1\n                : (st.dot[x - 1][y + 1] ? enc(x - 1, y + 1) : nwA[x - 1][y + 1]);\n        }\n    }\n    for (int x = N - 1; x >= 0; x--) {\n        for (int y = 0; y < N; y++) {\n            seA[x][y] = (x == N - 1 || y == 0) ? -1\n                : (st.dot[x + 1][y - 1] ? enc(x + 1, y - 1) : seA[x + 1][y - 1]);\n        }\n    }\n}\n\nvector<Cand> collect_top_candidates(const State& st, const EvalParams& prm) {\n    build_nearest(st);\n\n    vector<Cand> best;\n    best.reserve(prm.topKeep);\n\n    const double maxAdjBonus = max(0.0, prm.adjBonus) * 8.0;\n    const double maxPairBonus = max(0.0, prm.pairBonus) * 8.0;\n    const double minPenalty = max(0.0, prm.beta) * 4.0 + max(0.0, prm.gamma) * 1.0;\n\n    auto try_add = [&](int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4,\n                       int adj, int pairCnt) {\n        if (!inside(x3, y3)) return;\n        if (!st.dot[x3][y3]) return;\n\n        int l1 = max(abs(x2 - x1), abs(y2 - y1));\n        int l2 = max(abs(x4 - x1), abs(y4 - y1));\n        if (l1 <= 0 || l2 <= 0) return;\n\n        Cand c;\n        c.x1 = x1; c.y1 = y1;\n        c.x2 = x2; c.y2 = y2;\n        c.x3 = x3; c.y3 = y3;\n        c.x4 = x4; c.y4 = y4;\n        c.gain = W[x1][y1];\n        c.perim = 2 * (l1 + l2);\n        c.area = l1 * l2;\n        c.longSide = max(l1, l2);\n        if (c.perim > prm.maxPerim) return;\n\n        c.eval = c.gain\n               + prm.adjBonus * adj\n               + prm.pairBonus * pairCnt\n               - prm.beta * c.perim\n               - prm.gamma * c.area\n               - prm.longPenalty * (c.longSide - 1);\n\n        if (valid_rect(st, c)) push_top(best, c, prm.topKeep);\n    };\n\n    for (int id : cellOrder) {\n        int x = decx(id), y = decy(id);\n        if (st.dot[x][y]) continue;\n\n        if ((int)best.size() == prm.topKeep) {\n            double ub = W[x][y] + maxAdjBonus + maxPairBonus - minPenalty;\n            if (ub <= best.back().eval) break;\n        }\n\n        int e = eastA[x][y], w = westA[x][y], n = northA[x][y], s = southA[x][y];\n        int ne = neA[x][y], nw = nwA[x][y], se = seA[x][y], sw = swA[x][y];\n\n        int pairCnt = 0;\n        pairCnt += (e  != -1 && n  != -1);\n        pairCnt += (e  != -1 && s  != -1);\n        pairCnt += (w  != -1 && n  != -1);\n        pairCnt += (w  != -1 && s  != -1);\n        pairCnt += (ne != -1 && nw != -1);\n        pairCnt += (ne != -1 && se != -1);\n        pairCnt += (sw != -1 && nw != -1);\n        pairCnt += (sw != -1 && se != -1);\n\n        if (pairCnt == 0) continue;\n\n        int adj = adjacent_count8(st, x, y);\n\n        if (e != -1 && n != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (e != -1 && s != -1) {\n            int x2 = decx(e), y2 = decy(e);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (w != -1 && n != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(n), y4 = decy(n);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n        if (w != -1 && s != -1) {\n            int x2 = decx(w), y2 = decy(w);\n            int x4 = decx(s), y4 = decy(s);\n            try_add(x, y, x2, y2, x2, y4, x4, y4, adj, pairCnt);\n        }\n\n        if (ne != -1 && nw != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (ne != -1 && se != -1) {\n            int x2 = decx(ne), y2 = decy(ne);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (sw != -1 && nw != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(nw), y4 = decy(nw);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n        if (sw != -1 && se != -1) {\n            int x2 = decx(sw), y2 = decy(sw);\n            int x4 = decx(se), y4 = decy(se);\n            try_add(x, y, x2, y2, x2 + x4 - x, y2 + y4 - y, x4, y4, adj, pairCnt);\n        }\n    }\n\n    return best;\n}\n\nint choose_idx(const vector<Cand>& cand, int pickTop, double bias, XorShift64& rng) {\n    if (cand.empty()) return -1;\n    int m = min((int)cand.size(), pickTop);\n    if (m <= 1) return 0;\n    double r = rng.next_double();\n    int idx = (int)(pow(r, bias) * m);\n    if (idx >= m) idx = m - 1;\n    return idx;\n}\n\nState run_strategy(const State& initial, Strategy stg, XorShift64& rng,\n                   const function<double()>& elapsed, double TL, bool perturb) {\n    State st = initial;\n    st.ops.clear();\n    st.ops.reserve(N * N);\n\n    if (perturb) {\n        auto pert = [&](double v, double lo, double hi) {\n            return v * (lo + (hi - lo) * rng.next_double());\n        };\n        stg.betaHi = pert(stg.betaHi, 0.92, 1.08);\n        stg.betaLo = pert(stg.betaLo, 0.92, 1.08);\n        stg.gammaHi = pert(stg.gammaHi, 0.92, 1.08);\n        stg.gammaLo = pert(stg.gammaLo, 0.92, 1.08);\n        stg.adjHi = pert(stg.adjHi, 0.88, 1.12);\n        stg.adjLo = pert(stg.adjLo, 0.88, 1.12);\n        stg.pairHi = pert(stg.pairHi, 0.88, 1.12);\n        stg.pairLo = pert(stg.pairLo, 0.88, 1.12);\n        stg.longHi = pert(stg.longHi, 0.88, 1.12);\n        stg.longLo = pert(stg.longLo, 0.88, 1.12);\n        stg.bias = max(1.0, pert(stg.bias, 0.92, 1.08));\n        stg.pickTop = max(1, min(stg.topKeep, stg.pickTop + (int)(rng.next_u32() % 3) - 1));\n        if (stg.quotaMode) {\n            stg.stageLen = max(2, stg.stageLen + (int)(rng.next_u32() % 3) - 1);\n        }\n    }\n\n    int stage = 0;\n    int movesMade = 0;\n\n    while (elapsed() < TL) {\n        double prog = double(st.dotCount - M) / max(1, N * N - M);\n\n        EvalParams prm;\n        prm.beta = stg.betaHi * (1.0 - prog) + stg.betaLo * prog;\n        prm.gamma = stg.gammaHi * (1.0 - prog) + stg.gammaLo * prog;\n        prm.adjBonus = stg.adjHi * (1.0 - prog) + stg.adjLo * prog;\n        prm.pairBonus = stg.pairHi * (1.0 - prog) + stg.pairLo * prog;\n        prm.longPenalty = stg.longHi * (1.0 - prog) + stg.longLo * prog;\n        prm.topKeep = stg.topKeep;\n        prm.pickTop = stg.pickTop;\n        prm.bias = stg.bias;\n\n        vector<Cand> cand;\n\n        if (stg.quotaMode) {\n            int baseStage = min((int)stg.caps.size() - 1, movesMade / stg.stageLen);\n            bool found = false;\n            for (int s = baseStage; s < (int)stg.caps.size(); s++) {\n                prm.maxPerim = stg.caps[s];\n                cand = collect_top_candidates(st, prm);\n                if (!cand.empty()) {\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        } else {\n            if (stage >= (int)stg.caps.size()) stage = (int)stg.caps.size() - 1;\n            prm.maxPerim = stg.caps[stage];\n            cand = collect_top_candidates(st, prm);\n            if (cand.empty()) {\n                if (stage + 1 < (int)stg.caps.size()) {\n                    stage++;\n                    continue;\n                } else {\n                    break;\n                }\n            }\n        }\n\n        int idx = choose_idx(cand, prm.pickTop, prm.bias, rng);\n        apply_move(st, cand[idx]);\n        movesMade++;\n    }\n\n    return st;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State initial;\n    initial.N = N;\n\n    vector<pair<int, int>> initPts;\n    initPts.reserve(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        initial.dot[x][y] = 1;\n        initial.dotCount++;\n        initPts.push_back({x, y});\n    }\n\n    int c = (N - 1) / 2;\n    cellOrder.clear();\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            W[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n            cellOrder.push_back(enc(x, y));\n        }\n    }\n    sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n        int xa = decx(a), ya = decy(a);\n        int xb = decx(b), yb = decy(b);\n        if (W[xa][ya] != W[xb][yb]) return W[xa][ya] > W[xb][yb];\n        if (xa != xb) return xa < xb;\n        return ya < yb;\n    });\n\n    initial.sumW = 0;\n    for (auto [x, y] : initPts) initial.sumW += W[x][y];\n\n    uint64_t seed = 1469598103934665603ULL;\n    seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    for (auto [x, y] : initPts) {\n        seed ^= (uint64_t)(x * 131 + y * 10007 + 17) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n    XorShift64 rng(seed);\n\n    int extra = (N >= 49 ? 4 : (N >= 41 ? 2 : 0));\n    if (1LL * M * 18 >= 1LL * N * N) extra += 1;\n    bool dense = (120LL * M >= 11LL * N * N);\n\n    vector<Strategy> strategies = {\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.20, 0.18, 0.18, 0.020, 2.4, 0.4, 1.2, 0.1, 1.4, 0.1, 56 + extra, 5, 2.8, false, 0}, // 0\n        {{8, 12, 16, 24, INF_PERIM},    0.95, 0.12, 0.12, 0.010, 2.0, 0.2, 0.9, 0.1, 1.0, 0.1, 52 + extra, 4, 2.5, false, 0}, // 1\n        {{10, 14, 20, INF_PERIM},       0.70, 0.08, 0.08, 0.008, 1.4, 0.1, 0.7, 0.0, 0.7, 0.0, 44 + extra, 4, 2.2, false, 0}, // 2\n        {{INF_PERIM},                   0.45, 0.03, 0.040, 0.002, 0.8, 0.0, 0.5, 0.0, 0.3, 0.0, 40 + extra, 3, 2.0, false, 0}, // 3\n        {{18, 28, INF_PERIM},           0.35, 0.01, 0.020, 0.000, 0.5, 0.0, 0.4, 0.0, 0.4, 0.0, 40 + extra, 2, 1.7, false, 0}, // 4\n        {{8, 12, 16, 24, INF_PERIM},    1.00, 0.10, 0.12, 0.010, 1.8, 0.2, 0.8, 0.1, 0.9, 0.1, 48 + extra, 4, 2.3, true, 7},  // 5\n        {{6, 8, 10, 12, 16, INF_PERIM}, 1.30, 0.16, 0.20, 0.018, 2.2, 0.3, 1.0, 0.1, 1.2, 0.1, 56 + extra, 5, 2.7, true, 6},  // 6\n        {{10, 14, 20, INF_PERIM},       0.75, 0.06, 0.08, 0.006, 1.2, 0.1, 0.6, 0.0, 0.5, 0.0, 40 + extra, 3, 2.0, true, 8},  // 7\n        {{8, 12, 16, INF_PERIM},        0.90, 0.10, 0.10, 0.008, 1.6, 0.1, 1.6, 0.2, 0.8, 0.1, 52 + extra, 4, 2.4, false, 0}, // 8\n        {{INF_PERIM},                   0.30, 0.01, 0.020, 0.000, 0.4, 0.0, 0.8, 0.0, 0.2, 0.0, 40 + extra, 2, 1.6, false, 0}, // 9\n        {{6, 8, 10, 12, INF_PERIM},     1.10, 0.14, 0.14, 0.012, 2.0, 0.2, 0.9, 0.1, 1.8, 0.2, 52 + extra, 4, 2.6, false, 0}, // 10\n        {{8, 12, 20, INF_PERIM},        0.80, 0.05, 0.08, 0.004, 1.2, 0.0, 0.7, 0.0, 0.6, 0.0, 44 + extra, 3, 2.0, false, 0}, // 11\n    };\n\n    vector<int> detOrder;\n    vector<int> baseWeight((int)strategies.size(), 1);\n    auto setW = [&](int id, int w) { baseWeight[id] = w; };\n\n    if (!dense) {\n        detOrder = {0, 6, 8, 1, 10, 5, 2, 3};\n        setW(0, 9);\n        setW(6, 8);\n        setW(8, 7);\n        setW(1, 7);\n        setW(10, 6);\n        setW(5, 5);\n        setW(2, 4);\n        setW(3, 3);\n        setW(7, 3);\n        setW(11, 3);\n        setW(4, 2);\n        setW(9, 2);\n    } else {\n        detOrder = {1, 5, 3, 2, 4, 7, 10, 0};\n        setW(1, 8);\n        setW(5, 7);\n        setW(3, 6);\n        setW(2, 6);\n        setW(7, 5);\n        setW(4, 5);\n        setW(10, 4);\n        setW(0, 4);\n        setW(11, 4);\n        setW(8, 3);\n        setW(6, 3);\n        setW(9, 2);\n    }\n\n    auto stTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - stTime).count();\n    };\n\n    const double TL = 4.82;\n    const double detFrac = (N >= 55 ? 0.32 : 0.38);\n\n    long long bestSum = initial.sumW;\n    vector<Op> bestOps;\n    vector<long long> stratBest(strategies.size(), initial.sumW);\n\n    auto update_best = [&](const State& st) -> bool {\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n            return true;\n        }\n        return false;\n    };\n\n    auto run_and_record = [&](int sid, bool perturb, bool forceGreedy = false) -> pair<long long, bool> {\n        Strategy stg = strategies[sid];\n        if (forceGreedy) {\n            stg.pickTop = 1;\n            stg.bias = 1.0;\n        }\n        State st = run_strategy(initial, stg, rng, elapsed, TL, perturb);\n        stratBest[sid] = max(stratBest[sid], st.sumW);\n        bool newGlobal = update_best(st);\n        return {st.sumW, newGlobal};\n    };\n\n    vector<int> greedyFirst = dense ? vector<int>{1, 5} : vector<int>{0, 6};\n    for (int sid : greedyFirst) {\n        if (elapsed() >= TL * 0.10) break;\n        run_and_record(sid, false, true);\n    }\n\n    for (int sid : detOrder) {\n        if (elapsed() >= TL * detFrac) break;\n        run_and_record(sid, false, false);\n    }\n\n    vector<int> onlineBonus((int)strategies.size(), 0);\n    vector<int> adaptiveWeight((int)strategies.size(), 1);\n    vector<int> pool;\n\n    auto rebuild_weights_and_pool = [&]() {\n        adaptiveWeight = baseWeight;\n\n        vector<int> ids(strategies.size());\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (stratBest[a] != stratBest[b]) return stratBest[a] > stratBest[b];\n            return a < b;\n        });\n\n        vector<int> rankBonus = {10, 8, 6, 5, 4, 3, 2, 1};\n        for (int i = 0; i < (int)rankBonus.size() && i < (int)ids.size(); i++) {\n            adaptiveWeight[ids[i]] += rankBonus[i];\n        }\n\n        for (int sid = 0; sid < (int)strategies.size(); sid++) {\n            adaptiveWeight[sid] += min(onlineBonus[sid], 8);\n        }\n\n        pool.clear();\n        for (int sid = 0; sid < (int)strategies.size(); sid++) {\n            int w = max(1, adaptiveWeight[sid]);\n            for (int i = 0; i < w; i++) pool.push_back(sid);\n        }\n    };\n\n    rebuild_weights_and_pool();\n\n    int iter = 0;\n    while (elapsed() < TL) {\n        int sid;\n        if (!pool.empty() && (rng.next_u32() % 100) < 88) {\n            sid = pool[rng.next_u32() % pool.size()];\n        } else {\n            sid = rng.next_u32() % strategies.size();\n        }\n\n        long long prevStrat = stratBest[sid];\n        auto [score, newGlobal] = run_and_record(sid, true, false);\n\n        if (score > prevStrat) {\n            onlineBonus[sid] = min(12, onlineBonus[sid] + 1);\n        }\n        if (newGlobal) {\n            onlineBonus[sid] = min(12, onlineBonus[sid] + 2);\n        } else if (score * 1000 >= bestSum * 997) {\n            onlineBonus[sid] = min(12, onlineBonus[sid] + 1);\n        }\n\n        if ((iter & 31) == 31 && elapsed() < TL - 0.03) {\n            for (int i = 0; i < (int)onlineBonus.size(); i++) {\n                onlineBonus[i] = (onlineBonus[i] * 3) / 4;\n            }\n            rebuild_weights_and_pool();\n        }\n        iter++;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto& op : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << op[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 static_cast<uint32_t>(next_u64()); }\n};\n\nstruct Board {\n    array<uint8_t, 100> a;\n    Board() { a.fill(0); }\n};\n\nstruct PackedKey {\n    uint64_t w[4];\n    uint8_t turn;\n    bool operator==(const PackedKey& o) const {\n        return w[0] == o.w[0] && w[1] == o.w[1] && w[2] == o.w[2] && w[3] == o.w[3] && turn == o.turn;\n    }\n};\n\nstruct PackedKeyHash {\n    size_t operator()(const PackedKey& k) const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix(k.w[0]);\n        mix(k.w[1]);\n        mix(k.w[2]);\n        mix(k.w[3]);\n        mix(k.turn);\n        return (size_t)h;\n    }\n};\n\nstatic constexpr int N = 10;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\n// region ids:\n// 0: TL, 1: TR, 2: BL, 3: BR, 4: BC\nstruct Solver {\n    array<int, 101> f{};\n    Board board;\n\n    int target_region[4]{};   // flavor 1..3 -> region id\n    int dist_table[5][100]{};\n    int rem_after[101][4]{};\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    unordered_map<PackedKey, long long, PackedKeyHash> exact_memo;\n\n    Solver() {\n        start_time = chrono::steady_clock::now();\n        exact_memo.reserve(1 << 15);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void init_dist_table() {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int idx = r * N + c;\n                dist_table[0][idx] = r + c;                         // TL\n                dist_table[1][idx] = r + (N - 1 - c);              // TR\n                dist_table[2][idx] = (N - 1 - r) + c;              // BL\n                dist_table[3][idx] = (N - 1 - r) + (N - 1 - c);    // BR\n                dist_table[4][idx] = (N - 1 - r) + min(abs(c - 4), abs(c - 5)); // BC\n            }\n        }\n    }\n\n    void read_flavors() {\n        uint64_t seed = 1469598103934665603ull;\n        for (int i = 1; i <= 100; i++) {\n            cin >> f[i];\n            seed ^= (uint64_t)(f[i] + 1009 * i);\n            seed *= 1099511628211ull;\n        }\n        rng = XorShift64(seed ^ 0x9e3779b97f4a7c15ull);\n        init_dist_table();\n\n        for (int c = 1; c <= 3; c++) rem_after[100][c] = 0;\n        for (int t = 99; t >= 0; t--) {\n            for (int c = 1; c <= 3; c++) rem_after[t][c] = rem_after[t + 1][c];\n            rem_after[t][f[t + 1]]++;\n        }\n    }\n\n    static inline void place(Board& b, int p, int flavor) {\n        int cnt = 0;\n        for (int i = 0; i < 100; i++) {\n            if (b.a[i] == 0) {\n                ++cnt;\n                if (cnt == p) {\n                    b.a[i] = (uint8_t)flavor;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline Board tilt(const Board& in, int dir) {\n        Board out;\n        if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                int wr = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr++ * N + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < N; c++) {\n                int wr = N - 1;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = in.a[r * N + c];\n                    if (v) out.a[wr-- * N + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = 0;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc++] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < N; r++) {\n                int base = r * N;\n                int wc = N - 1;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = in.a[base + c];\n                    if (v) out.a[base + wc--] = v;\n                }\n            }\n        }\n        return out;\n    }\n\n    static inline int component_square_sum(const Board& b) {\n        bool vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; s++) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            int qh = 0, qt = 0;\n            q[qt++] = s;\n            vis[s] = true;\n            int sz = 0;\n\n            while (qh < qt) {\n                int v = q[qh++];\n                ++sz;\n                int r = v / N, c = v % N;\n\n                if (r > 0) {\n                    int nv = v - N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (r + 1 < N) {\n                    int nv = v + N;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n                if (c + 1 < N) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = true, q[qt++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    inline long long heuristic(const Board& b, int turn) const {\n        int rowcnt[10][4] = {};\n        int colcnt[10][4] = {};\n        int same_adj = 0, diff_adj = 0;\n        int dist_pen = 0;\n\n        for (int idx = 0; idx < 100; idx++) {\n            uint8_t col = b.a[idx];\n            if (!col) continue;\n            int r = idx / N, c = idx % N;\n            rowcnt[r][col]++;\n            colcnt[c][col]++;\n\n            int mult = 1 + rem_after[turn][col] / 18;\n            dist_pen += dist_table[target_region[col]][idx] * mult;\n\n            if (c + 1 < N) {\n                uint8_t v = b.a[idx + 1];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t v = b.a[idx + N];\n                if (v) {\n                    if (v == col) same_adj++;\n                    else diff_adj++;\n                }\n            }\n        }\n\n        int purity = 0;\n        for (int i = 0; i < N; i++) {\n            for (int col = 1; col <= 3; col++) {\n                purity += rowcnt[i][col] * rowcnt[i][col];\n                purity += colcnt[i][col] * colcnt[i][col];\n            }\n        }\n\n        int block_score = 0;\n        for (int r = 0; r + 1 < N; r++) {\n            for (int c = 0; c + 1 < N; c++) {\n                int cnt[4] = {};\n                uint8_t v1 = b.a[r * N + c];\n                uint8_t v2 = b.a[r * N + c + 1];\n                uint8_t v3 = b.a[(r + 1) * N + c];\n                uint8_t v4 = b.a[(r + 1) * N + c + 1];\n                if (v1) cnt[v1]++;\n                if (v2) cnt[v2]++;\n                if (v3) cnt[v3]++;\n                if (v4) cnt[v4]++;\n\n                int kinds = 0, occ = 0, sq = 0;\n                for (int col = 1; col <= 3; col++) {\n                    if (cnt[col]) {\n                        kinds++;\n                        occ += cnt[col];\n                        sq += cnt[col] * cnt[col];\n                    }\n                }\n                block_score += sq;\n                if (kinds >= 2) block_score -= 2 * occ * (kinds - 1);\n            }\n        }\n\n        int comp2 = component_square_sum(b);\n\n        int wComp = 28 + turn / 4;\n        int wSame = 16;\n        int wDiff = 13;\n        int wPurity = 2;\n        int wBlock = 5;\n        int wTarget = max(2, 19 - turn / 6);\n\n        long long val = 0;\n        val += 1LL * wComp * comp2;\n        val += 1LL * wSame * same_adj;\n        val -= 1LL * wDiff * diff_adj;\n        val += 1LL * wPurity * purity;\n        val += 1LL * wBlock * block_score;\n        val -= 1LL * wTarget * dist_pen;\n        return val;\n    }\n\n    inline int greedy_action(const Board& b, int turn) const {\n        int best_dir = 0;\n        long long best_score = LLONG_MIN;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(b, dir);\n            long long sc = heuristic(nb, turn);\n            if (sc > best_score) {\n                best_score = sc;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void choose_best_mapping() {\n        vector<array<int, 3>> templates = {\n            {0, 1, 4}, // TL, TR, BC\n            {0, 1, 3}  // TL, TR, BR\n        };\n\n        const int TRIALS = 6;\n        int sampled_p[TRIALS][101]{};\n        for (int tr = 0; tr < TRIALS; tr++) {\n            for (int turn = 1; turn <= 100; turn++) {\n                int empties = 101 - turn;\n                sampled_p[tr][turn] = (int)(rng.next_u32() % empties) + 1;\n            }\n        }\n\n        array<int, 3> perm = {0, 1, 2};\n        long long best_total = -1;\n        int best_map[4] = {0, 0, 1, 4};\n\n        for (auto tpl : templates) {\n            sort(perm.begin(), perm.end());\n            do {\n                target_region[1] = tpl[perm[0]];\n                target_region[2] = tpl[perm[1]];\n                target_region[3] = tpl[perm[2]];\n\n                long long total = 0;\n                for (int tr = 0; tr < TRIALS; tr++) {\n                    Board b;\n                    for (int turn = 1; turn <= 100; turn++) {\n                        place(b, sampled_p[tr][turn], f[turn]);\n                        int dir = greedy_action(b, turn);\n                        b = tilt(b, dir);\n                    }\n                    total += component_square_sum(b);\n                }\n\n                if (total > best_total) {\n                    best_total = total;\n                    for (int c = 1; c <= 3; c++) best_map[c] = target_region[c];\n                }\n            } while (next_permutation(perm.begin(), perm.end()));\n        }\n\n        for (int c = 1; c <= 3; c++) target_region[c] = best_map[c];\n    }\n\n    PackedKey pack_key(const Board& b, int turn) const {\n        PackedKey k{};\n        k.w[0] = k.w[1] = k.w[2] = k.w[3] = 0;\n        for (int i = 0; i < 100; i++) {\n            uint64_t v = b.a[i];\n            int bit = 2 * i;\n            int blk = bit >> 6;\n            int off = bit & 63;\n            k.w[blk] |= (v << off);\n        }\n        k.turn = (uint8_t)turn;\n        return k;\n    }\n\n    long long exact_value(const Board& b, int turn) {\n        if (turn == 100) return component_square_sum(b);\n\n        PackedKey key = pack_key(b, turn);\n        auto it = exact_memo.find(key);\n        if (it != exact_memo.end()) return it->second;\n\n        int empties = 100 - turn;\n        long long sum = 0;\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = exact_value(nb, turn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n\n        exact_memo.emplace(key, sum);\n        return sum;\n    }\n\n    long long limited_value(const Board& b, int turn, int depth) {\n        if (turn == 100) return component_square_sum(b);\n        if (depth == 0) return heuristic(b, turn);\n\n        int empties = 100 - turn;\n        long long sum = 0;\n\n        for (int p = 1; p <= empties; p++) {\n            Board placed = b;\n            place(placed, p, f[turn + 1]);\n\n            long long best = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(placed, dir);\n                long long v = limited_value(nb, turn + 1, depth - 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n        return sum;\n    }\n\n    int choose_depth(int rem_future) const {\n        double t = elapsed();\n        if (t > 1.82) return 1;\n        if (rem_future <= 4 && t < 1.72) return 100; // exact endgame\n        if (rem_future <= 7 && t < 1.70) return 3;\n        if (rem_future <= 20 && t < 1.78) return 2;\n        return 1;\n    }\n\n    int decide_action(int turn) {\n        int rem_future = 100 - turn;\n\n        if (rem_future == 0) {\n            int best_dir = 0;\n            int best_score = -1;\n            long long best_h = LLONG_MIN;\n            for (int dir = 0; dir < 4; dir++) {\n                Board nb = tilt(board, dir);\n                int sc = component_square_sum(nb);\n                long long h = heuristic(nb, turn);\n                if (sc > best_score || (sc == best_score && h > best_h)) {\n                    best_score = sc;\n                    best_h = h;\n                    best_dir = dir;\n                }\n            }\n            return best_dir;\n        }\n\n        int depth = choose_depth(rem_future);\n\n        array<pair<long long, int>, 4> order;\n        for (int dir = 0; dir < 4; dir++) {\n            Board nb = tilt(board, dir);\n            order[dir] = {heuristic(nb, turn), dir};\n        }\n        sort(order.begin(), order.end(), greater<>());\n\n        long long best = LLONG_MIN;\n        long long best_h = LLONG_MIN;\n        int best_dir = 0;\n\n        if (depth == 100) exact_memo.clear();\n\n        for (auto [_, dir] : order) {\n            Board nb = tilt(board, dir);\n            long long v = (depth == 100 ? exact_value(nb, turn) : limited_value(nb, turn, depth));\n            long long h = heuristic(nb, turn);\n            if (v > best || (v == best && h > best_h)) {\n                best = v;\n                best_h = h;\n                best_dir = dir;\n            }\n        }\n        return best_dir;\n    }\n\n    void solve() {\n        read_flavors();\n        choose_best_mapping();\n\n        for (int turn = 1; turn <= 100; turn++) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place(board, p, f[turn]);\n            int dir = decide_action(turn);\n            board = tilt(board, dir);\n\n            cout << DIR_CH[dir] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\n// ============================================================\n// Exact solver for eps = 0\n// ============================================================\n\nstruct ExactNoNoiseSolver {\n    int M, N, C;\n    vector<vector<int>> perm_maps;\n    vector<uint32_t> reps;\n    unordered_map<uint32_t, int> id_of;\n\n    static int unlabeled_count(int n) {\n        if (n == 4) return 11;\n        if (n == 5) return 34;\n        if (n == 6) return 156;\n        return 0;\n    }\n\n    static vector<pair<int,int>> edge_list(int n) {\n        vector<pair<int,int>> e;\n        for (int i = 0; i < n; ++i)\n            for (int j = i + 1; j < n; ++j)\n                e.push_back({i, j});\n        return e;\n    }\n\n    uint32_t permute_mask(uint32_t mask, const vector<int>& mp) const {\n        uint32_t res = 0;\n        while (mask) {\n            int b = __builtin_ctz(mask);\n            mask &= mask - 1;\n            res |= (1u << mp[b]);\n        }\n        return res;\n    }\n\n    uint32_t canonical(uint32_t mask) const {\n        uint32_t best = UINT32_MAX;\n        for (const auto& mp : perm_maps) {\n            uint32_t x = permute_mask(mask, mp);\n            if (x < best) best = x;\n        }\n        return best;\n    }\n\n    string mask_to_string(uint32_t mask) const {\n        string s;\n        s.reserve(C);\n        for (int i = 0; i < C; ++i) s.push_back(((mask >> i) & 1u) ? '1' : '0');\n        return s;\n    }\n\n    uint32_t string_to_mask(const string& s) const {\n        uint32_t mask = 0;\n        for (int i = 0; i < (int)s.size(); ++i) if (s[i] == '1') mask |= (1u << i);\n        return mask;\n    }\n\n    ExactNoNoiseSolver(int M_) : M(M_) {\n        if (M <= unlabeled_count(4)) N = 4;\n        else if (M <= unlabeled_count(5)) N = 5;\n        else N = 6;\n        C = N * (N - 1) / 2;\n\n        auto edges = edge_list(N);\n        vector<vector<int>> pos(N, vector<int>(N, -1));\n        for (int i = 0; i < C; ++i) {\n            auto [u, v] = edges[i];\n            pos[u][v] = pos[v][u] = i;\n        }\n\n        vector<int> p(N);\n        iota(p.begin(), p.end(), 0);\n        do {\n            vector<int> mp(C);\n            for (int i = 0; i < C; ++i) {\n                auto [u, v] = edges[i];\n                int a = p[u], b = p[v];\n                if (a > b) swap(a, b);\n                mp[i] = pos[a][b];\n            }\n            perm_maps.push_back(move(mp));\n        } while (next_permutation(p.begin(), p.end()));\n\n        set<uint32_t> seen;\n        uint32_t total = 1u << C;\n        for (uint32_t mask = 0; mask < total; ++mask) {\n            uint32_t can = canonical(mask);\n            if (seen.insert(can).second) reps.push_back(can);\n        }\n        sort(reps.begin(), reps.end());\n        reps.resize(M);\n        for (int i = 0; i < M; ++i) id_of[reps[i]] = i;\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (uint32_t m : reps) cout << mask_to_string(m) << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        uint32_t mask = string_to_mask(H);\n        uint32_t can = canonical(mask);\n        auto it = id_of.find(can);\n        if (it == id_of.end()) return 0;\n        return it->second;\n    }\n};\n\n// ============================================================\n// RNG\n// ============================================================\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    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// ============================================================\n// General solver\n// Equal-block threshold graphs + degree decoder + weak tie-break\n// ============================================================\n\nstruct GeneralSolver {\n    struct Candidate {\n        uint16_t mask;\n        vector<int> seq; // sorted block degree sequence, length R\n    };\n\n    struct ComboResult {\n        double proxy = -1.0;\n        int R = -1, B = -1, N = -1;\n        vector<Candidate> selected;\n    };\n\n    struct GraphCode {\n        uint16_t mask;\n        vector<int> ideal_deg;      // full sorted degree sequence, length N\n        vector<uint8_t> edgeBits;   // upper triangle\n        string gstr;\n    };\n\n    int M;\n    double eps, a, c;\n\n    int R, B, N, C;\n    vector<GraphCode> codes;\n    vector<int> eu, ev;\n\n    // Final decoder pack\n    int S;\n    int TOPL;\n    double mu_ideal;\n    double lambda_nd;\n    vector<vector<uint16_t>> feat_samples; // [M*S][2N]\n    vector<vector<float>> expected_deg;    // [M][N]\n\n    static int seq_dist2(const vector<int>& x, const vector<int>& y) {\n        int s = 0;\n        for (int i = 0; i < (int)x.size(); ++i) {\n            int d = x[i] - y[i];\n            s += d * d;\n        }\n        return s;\n    }\n\n    static vector<int> block_degree_seq(uint16_t mask, int R, int B) {\n        vector<int> deg(R);\n        int suf = 0;\n        for (int i = R - 1; i >= 0; --i) {\n            int z = (mask >> i) & 1u;\n            deg[i] = B * suf + (z ? (B - 1 + B * i) : 0);\n            suf += z;\n        }\n        sort(deg.begin(), deg.end());\n        return deg;\n    }\n\n    static string build_graph_string(uint16_t mask, int R, int B, vector<uint8_t>* edgeBits = nullptr) {\n        int N = R * B;\n        string g;\n        g.reserve(N * (N - 1) / 2);\n        if (edgeBits) edgeBits->clear(), edgeBits->reserve(N * (N - 1) / 2);\n\n        for (int u = 0; u < N; ++u) {\n            int bu = u / B;\n            for (int v = u + 1; v < N; ++v) {\n                int bv = v / B;\n                bool e;\n                if (bu == bv) e = ((mask >> bu) & 1u);\n                else e = ((mask >> max(bu, bv)) & 1u); // later block decides\n                g.push_back(e ? '1' : '0');\n                if (edgeBits) edgeBits->push_back((uint8_t)e);\n            }\n        }\n        return g;\n    }\n\n    double eval_proxy(const vector<Candidate>& sel, int B, int N) const {\n        double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n        double avg_p = 0.0;\n        const double SQRT2 = sqrt(2.0);\n\n        for (int i = 0; i < M; ++i) {\n            int best_d2 = INT_MAX;\n            for (int j = 0; j < M; ++j) if (i != j) {\n                best_d2 = min(best_d2, seq_dist2(sel[i].seq, sel[j].seq));\n            }\n            double p = 0.0;\n            if (sigma > 1e-15) {\n                double D = a * sqrt((double)B * best_d2);\n                double x = D / (2.0 * sigma);\n                p = 0.5 * erfc(x / SQRT2);\n            }\n            avg_p += p;\n        }\n        avg_p /= M;\n\n        double per_query = max(0.0, 1.0 - 0.1 * avg_p);\n        return pow(per_query, 100.0) / N;\n    }\n\n    vector<Candidate> greedy_select(const vector<Candidate>& cands, int start_idx) const {\n        int CC = (int)cands.size();\n        vector<int> minD(CC, INT_MAX);\n        vector<char> used(CC, 0);\n        vector<int> sel_idx;\n        sel_idx.reserve(M);\n\n        auto add_one = [&](int idx) {\n            used[idx] = 1;\n            sel_idx.push_back(idx);\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[idx].seq, cands[i].seq);\n                if (d2 < minD[i]) minD[i] = d2;\n            }\n        };\n\n        add_one(start_idx);\n        if (M >= 2) {\n            int far = -1, far_d = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int d2 = seq_dist2(cands[start_idx].seq, cands[i].seq);\n                if (d2 > far_d) far_d = d2, far = i;\n            }\n            add_one(far);\n        }\n\n        while ((int)sel_idx.size() < M) {\n            int best = -1, best_d = -1, best_sum = -1;\n            for (int i = 0; i < CC; ++i) if (!used[i]) {\n                int candd = minD[i];\n                int sumd = 0;\n                for (int x : sel_idx) sumd += seq_dist2(cands[i].seq, cands[x].seq);\n                if (candd > best_d || (candd == best_d && sumd > best_sum)) {\n                    best_d = candd;\n                    best_sum = sumd;\n                    best = i;\n                }\n            }\n            add_one(best);\n        }\n\n        vector<Candidate> sel;\n        sel.reserve(M);\n        for (int idx : sel_idx) sel.push_back(cands[idx]);\n        sort(sel.begin(), sel.end(), [](const Candidate& lhs, const Candidate& rhs) {\n            return lhs.seq < rhs.seq;\n        });\n        return sel;\n    }\n\n    ComboResult try_combo(int R, int B) const {\n        ComboResult res;\n        res.R = R;\n        res.B = B;\n        res.N = R * B;\n\n        map<vector<int>, uint16_t> uniq;\n        uint16_t total = (uint16_t)(1u << R);\n        for (uint16_t mask = 0; mask < total; ++mask) {\n            vector<int> seq = block_degree_seq(mask, R, B);\n            if (!uniq.count(seq)) uniq.emplace(seq, mask);\n        }\n\n        vector<Candidate> cands;\n        cands.reserve(uniq.size());\n        for (auto& kv : uniq) cands.push_back({kv.second, kv.first});\n        if ((int)cands.size() < M) return res;\n\n        int CC = (int)cands.size();\n        vector<int> sums(CC);\n        for (int i = 0; i < CC; ++i) {\n            sums[i] = accumulate(cands[i].seq.begin(), cands[i].seq.end(), 0);\n        }\n\n        int min_idx = 0, max_idx = 0;\n        for (int i = 1; i < CC; ++i) {\n            if (sums[i] < sums[min_idx]) min_idx = i;\n            if (sums[i] > sums[max_idx]) max_idx = i;\n        }\n\n        vector<pair<int,int>> ord;\n        ord.reserve(CC);\n        for (int i = 0; i < CC; ++i) ord.push_back({sums[i], i});\n        sort(ord.begin(), ord.end());\n        int med_idx = ord[CC / 2].second;\n\n        vector<int> starts = {min_idx, max_idx, med_idx};\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int st : starts) {\n            vector<Candidate> sel = greedy_select(cands, st);\n            double pr = eval_proxy(sel, B, R * B);\n            if (pr > res.proxy) {\n                res.proxy = pr;\n                res.selected = move(sel);\n            }\n        }\n        return res;\n    }\n\n    void prepare_pairs(int N_) {\n        N = N_;\n        C = N * (N - 1) / 2;\n        eu.clear();\n        ev.clear();\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n    }\n\n    static vector<uint16_t> sample_noisy_feature(\n        int N,\n        const vector<int>& eu,\n        const vector<int>& ev,\n        const vector<uint8_t>& edgeBits,\n        uint32_t thr,\n        SplitMix64& rng\n    ) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int C = (int)edgeBits.size();\n        for (int idx = 0; idx < C; ++idx) {\n            bool b = edgeBits[idx];\n            if (rng.next_u32() < thr) b = !b;\n            if (b) {\n                int u = eu[idx], v = ev[idx];\n                adj[u][v] = adj[v][u] = 1;\n                ++deg[u];\n                ++deg[v];\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static vector<uint16_t> feature_from_string(const string& H, int N) {\n        static uint8_t adj[100][100];\n        int deg[100];\n        for (int i = 0; i < N; ++i) {\n            deg[i] = 0;\n            memset(adj[i], 0, N);\n        }\n\n        int p = 0;\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                if (H[p++] == '1') {\n                    adj[i][j] = adj[j][i] = 1;\n                    ++deg[i];\n                    ++deg[j];\n                }\n            }\n        }\n\n        vector<pair<uint16_t,uint16_t>> arr;\n        arr.reserve(N);\n        for (int v = 0; v < N; ++v) {\n            int s = 0;\n            for (int u = 0; u < N; ++u) if (adj[v][u]) s += deg[u];\n            arr.push_back({(uint16_t)deg[v], (uint16_t)s});\n        }\n        sort(arr.begin(), arr.end());\n\n        vector<uint16_t> feat;\n        feat.reserve(2 * N);\n        for (auto [d, s] : arr) {\n            feat.push_back(d);\n            feat.push_back(s);\n        }\n        return feat;\n    }\n\n    static double degree_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int M,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg,\n        double mu_ideal\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i] - (int)s[2 * i]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        double ideal = 0.0;\n        for (int i = 0; i < N; ++i) ideal += fabs((double)qfeat[2 * i] - expected_deg[g][i]);\n\n        return avgBest + mu_ideal * ideal;\n    }\n\n    static double ndsum_cost_knn(\n        const vector<uint16_t>& qfeat,\n        int g,\n        int S,\n        int N,\n        const vector<vector<uint16_t>>& feat_samples\n    ) {\n        int kbest = min(3, S);\n        int b1 = INT_MAX, b2 = INT_MAX, b3 = INT_MAX;\n\n        for (int t = 0; t < S; ++t) {\n            const auto& s = feat_samples[g * S + t];\n            int d = 0;\n            for (int i = 0; i < N; ++i) d += abs((int)qfeat[2 * i + 1] - (int)s[2 * i + 1]);\n            if (d < b1) { b3 = b2; b2 = b1; b1 = d; }\n            else if (d < b2) { b3 = b2; b2 = d; }\n            else if (d < b3) { b3 = d; }\n        }\n\n        double avgBest;\n        if (kbest == 1) avgBest = b1;\n        else if (kbest == 2) avgBest = 0.5 * (b1 + b2);\n        else avgBest = (b1 + b2 + b3) / 3.0;\n\n        return avgBest / max(1, N);\n    }\n\n    static int decode_feature(\n        const vector<uint16_t>& qfeat,\n        int M,\n        int S,\n        int N,\n        int TOPL,\n        double mu_ideal,\n        double lambda_nd,\n        const vector<vector<uint16_t>>& feat_samples,\n        const vector<vector<float>>& expected_deg\n    ) {\n        vector<pair<double,int>> deg_rank;\n        deg_rank.reserve(M);\n        for (int g = 0; g < M; ++g) {\n            double dc = degree_cost_knn(qfeat, g, M, S, N, feat_samples, expected_deg, mu_ideal);\n            deg_rank.push_back({dc, g});\n        }\n\n        if (TOPL < M) {\n            nth_element(deg_rank.begin(), deg_rank.begin() + TOPL, deg_rank.end());\n            deg_rank.resize(TOPL);\n        }\n\n        int best_id = 0;\n        double best_cost = 1e300;\n\n        for (auto [dc, g] : deg_rank) {\n            double nc = ndsum_cost_knn(qfeat, g, S, N, feat_samples);\n            double total = dc + lambda_nd * nc;\n            if (total < best_cost) {\n                best_cost = total;\n                best_id = g;\n            }\n        }\n        return best_id;\n    }\n\n    vector<GraphCode> build_graph_codes_from_combo(const ComboResult& combo) const {\n        vector<GraphCode> ret;\n        ret.reserve(M);\n        int N = combo.R * combo.B;\n\n        for (const auto& cand : combo.selected) {\n            vector<uint8_t> bits;\n            string g = build_graph_string(cand.mask, combo.R, combo.B, &bits);\n\n            vector<int> ideal_deg;\n            ideal_deg.reserve(N);\n            for (int d : cand.seq) {\n                for (int t = 0; t < combo.B; ++t) ideal_deg.push_back(d);\n            }\n\n            ret.push_back({cand.mask, move(ideal_deg), move(bits), move(g)});\n        }\n        return ret;\n    }\n\n    static double validate_combo(\n        int M,\n        double eps,\n        const ComboResult& combo,\n        const vector<GraphCode>& codes\n    ) {\n        int N = combo.N;\n        int C = N * (N - 1) / 2;\n        vector<int> eu, ev;\n        eu.reserve(C);\n        ev.reserve(C);\n        for (int i = 0; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                eu.push_back(i);\n                ev.push_back(j);\n            }\n        }\n\n        int S_train, T_val, TOPL;\n        double mu_ideal = 0.25;\n        double lambda_nd;\n        if (eps < 0.08) {\n            S_train = 4;\n            T_val = 2;\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            S_train = 6;\n            T_val = 2;\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            S_train = 8;\n            T_val = 2;\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n\n        vector<vector<uint16_t>> feat_samples(M * S_train);\n        vector<vector<float>> expected_deg(M, vector<float>(N));\n        double a = 1.0 - 2.0 * eps;\n        double c = eps * (N - 1);\n\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x1234567890abcdefULL + (uint64_t)N * 1009 + M * 17 + (uint64_t)(eps * 1000 + 0.5));\n\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S_train; ++t) {\n                feat_samples[g * S_train + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n\n        int correct = 0, total = 0;\n        for (int tg = 0; tg < M; ++tg) {\n            for (int tv = 0; tv < T_val; ++tv) {\n                auto q = sample_noisy_feature(N, eu, ev, codes[tg].edgeBits, thr, rng);\n                int pred = decode_feature(q, M, S_train, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n                if (pred == tg) ++correct;\n                ++total;\n            }\n        }\n\n        double acc = (double)correct / total;\n        return 100.0 * (1.0 - acc) * log(0.9) - log((double)N);\n    }\n\n    GeneralSolver(int M_, double eps_) : M(M_), eps(eps_) {\n        a = 1.0 - 2.0 * eps;\n        c = 0.0;\n\n        vector<ComboResult> pool;\n\n        int minR = 0;\n        while ((1u << minR) < (unsigned)M) ++minR;\n        minR = max(minR, 4);\n        int maxR = min(10, minR + 5);\n\n        for (int r = minR; r <= maxR; ++r) {\n            int maxB = 100 / r;\n            for (int b = 1; b <= maxB; ++b) {\n                ComboResult cur = try_combo(r, b);\n                if (cur.proxy > 0) pool.push_back(move(cur));\n            }\n        }\n\n        if (pool.empty()) {\n            // conservative fallback\n            R = minR;\n            B = 100 / R;\n            N = R * B;\n            prepare_pairs(N);\n\n            vector<Candidate> fallback;\n            for (int k = 0; k < M; ++k) {\n                uint16_t mask = (uint16_t)k;\n                fallback.push_back({mask, block_degree_seq(mask, R, B)});\n            }\n            sort(fallback.begin(), fallback.end(), [](const Candidate& x, const Candidate& y) {\n                return x.seq < y.seq;\n            });\n\n            ComboResult combo;\n            combo.R = R; combo.B = B; combo.N = N; combo.selected = fallback;\n            codes = build_graph_codes_from_combo(combo);\n        } else {\n            sort(pool.begin(), pool.end(), [](const ComboResult& x, const ComboResult& y) {\n                return x.proxy > y.proxy;\n            });\n\n            int checkTop = min<int>(8, pool.size());\n            int best_i = 0;\n            double best_val = -1e300;\n\n            for (int i = 0; i < checkTop; ++i) {\n                auto tmp_codes = build_graph_codes_from_combo(pool[i]);\n                double val = validate_combo(M, eps, pool[i], tmp_codes);\n                if (val > best_val) {\n                    best_val = val;\n                    best_i = i;\n                }\n            }\n\n            R = pool[best_i].R;\n            B = pool[best_i].B;\n            N = pool[best_i].N;\n            codes = build_graph_codes_from_combo(pool[best_i]);\n        }\n\n        prepare_pairs(N);\n        c = eps * (N - 1);\n\n        if (eps < 0.05) S = 8;\n        else if (eps < 0.15) S = 12;\n        else if (eps < 0.25) S = 16;\n        else S = 20;\n        if (M < 20) S += 4;\n        S = min(S, 24);\n\n        if (eps < 0.08) {\n            TOPL = min(M, 10);\n            lambda_nd = 0.14;\n        } else if (eps < 0.18) {\n            TOPL = min(M, 12);\n            lambda_nd = 0.10;\n        } else {\n            TOPL = min(M, 16);\n            lambda_nd = 0.07;\n        }\n        mu_ideal = 0.25;\n\n        feat_samples.assign(M * S, {});\n        expected_deg.assign(M, vector<float>(N));\n        for (int g = 0; g < M; ++g) {\n            for (int i = 0; i < N; ++i) {\n                expected_deg[g][i] = (float)(c + a * codes[g].ideal_deg[i]);\n            }\n        }\n\n        uint32_t thr = (uint32_t)llround(eps * 4294967296.0);\n        SplitMix64 rng(0x3141592653589793ULL + (uint64_t)N * 10007 + M * 911 + (uint64_t)(eps * 1000 + 0.5));\n        for (int g = 0; g < M; ++g) {\n            for (int t = 0; t < S; ++t) {\n                feat_samples[g * S + t] = sample_noisy_feature(N, eu, ev, codes[g].edgeBits, thr, rng);\n            }\n        }\n    }\n\n    void output_initial() const {\n        cout << N << '\\n';\n        for (const auto& code : codes) cout << code.gstr << '\\n';\n        cout.flush();\n    }\n\n    int predict(const string& H) const {\n        auto qfeat = feature_from_string(H, N);\n        return decode_feature(qfeat, M, S, N, TOPL, mu_ideal, lambda_nd, feat_samples, expected_deg);\n    }\n};\n\n// ============================================================\n// main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    if (fabs(eps) < 1e-12) {\n        ExactNoNoiseSolver solver(M);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        GeneralSolver solver(M, eps);\n        solver.output_initial();\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            if (!(cin >> H)) return 0;\n            int ans = solver.predict(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic const ll INF64 = (1LL << 60);\nstatic const int MAXD = 30;\n\nstruct Solver {\n    struct Edge {\n        int u, v;\n        ll w;\n        int cell = 0;\n        double usage = 0.0;\n        ll detour = 0;\n        double imp = 1.0;\n    };\n    struct Adj {\n        int to, id;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<pair<int,int>> coord;\n    vector<vector<Adj>> g;\n    vector<int> degv;\n    vector<double> vCoef; // low-degree vertices get larger penalty\n\n    // assignment\n    vector<int> dayOf;\n    vector<int> posInDay;\n    vector<vector<int>> dayEdges;\n    vector<int> dayCnt;\n    vector<double> dayLoad;\n\n    // counts\n    vector<array<int, MAXD>> cntV;\n    vector<array<int, MAXD>> cntCell;\n\n    // dangerous edge-pair conflicts\n    vector<vector<int>> conflicts;\n    int bitBlocks;\n    vector<unsigned long long> confBitsFlat;\n    vector<array<int, MAXD>> confCnt; // confCnt[e][d] = # conflicting edges of e assigned to day d\n\n    // geometry\n    int G, C;\n\n    // proxy weights\n    double WA, WB, WC, WQ;\n\n    // sampled evaluation\n    vector<int> landmarks;\n    int L_imp = 12;\n    int L_eval = 5;\n    vector<vector<ll>> origEvalDist;\n    vector<ll> dayScore;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver() {\n        rng.seed((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n        st = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    inline double comb2(int x) const {\n        return 0.5 * x * (x - 1);\n    }\n\n    inline int bit_index(int e, int b) const {\n        return e * bitBlocks + b;\n    }\n\n    inline bool is_conflict(int a, int b) const {\n        return (confBitsFlat[bit_index(a, b >> 6)] >> (b & 63)) & 1ULL;\n    }\n\n    void add_conflict(int a, int b) {\n        if (a == b) return;\n        if (is_conflict(a, b)) return;\n        confBitsFlat[bit_index(a, b >> 6)] |= 1ULL << (b & 63);\n        confBitsFlat[bit_index(b, a >> 6)] |= 1ULL << (a & 63);\n        conflicts[a].push_back(b);\n        conflicts[b].push_back(a);\n    }\n\n    void read_input() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        degv.assign(N, 0);\n\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            ll w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i] = {u, v, w};\n            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            degv[u]++;\n            degv[v]++;\n        }\n\n        coord.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> coord[i].first >> coord[i].second;\n        }\n\n        vCoef.resize(N);\n        for (int v = 0; v < N; v++) {\n            vCoef[v] = 1.0 / max(1, degv[v] - 1);\n        }\n\n        G = max(4, min(6, (int)llround(sqrt((double)D)) + 1));\n        C = G * G;\n        for (int i = 0; i < M; i++) {\n            double mx = (coord[edges[i].u].first + coord[edges[i].v].first) * 0.5;\n            double my = (coord[edges[i].u].second + coord[edges[i].v].second) * 0.5;\n            int cx = min(G - 1, max(0, (int)(mx * G / 1001.0)));\n            int cy = min(G - 1, max(0, (int)(my * G / 1001.0)));\n            edges[i].cell = cy * G + cx;\n        }\n\n        dayOf.assign(M, -1);\n        posInDay.assign(M, -1);\n        dayEdges.assign(D, {});\n        dayCnt.assign(D, 0);\n        dayLoad.assign(D, 0.0);\n\n        cntV.assign(N, {});\n        for (auto &a : cntV) a.fill(0);\n\n        cntCell.assign(C, {});\n        for (auto &a : cntCell) a.fill(0);\n\n        conflicts.assign(M, {});\n        bitBlocks = (M + 63) >> 6;\n        confBitsFlat.assign(M * bitBlocks, 0ULL);\n        confCnt.assign(M, {});\n        for (auto &a : confCnt) a.fill(0);\n\n        WA = 0.025;\n        WB = 4.5;\n        WC = 0.6;\n        WQ = 0.008;\n    }\n\n    void dijkstra_full(int src,\n                       vector<ll> &dist,\n                       int skipEdge = -1,\n                       int skipDay = -1,\n                       int target = -1,\n                       vector<int> *parV = nullptr,\n                       vector<int> *parE = nullptr) {\n        dist.assign(N, INF64);\n        if (parV) parV->assign(N, -1);\n        if (parE) parE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n            if (v == target) return;\n\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == skipEdge) continue;\n                if (skipDay >= 0 && dayOf[id] == skipDay) continue;\n                int to = ad.to;\n                ll nd = cd + edges[id].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parV) (*parV)[to] = v;\n                    if (parE) (*parE)[to] = id;\n                    pq.push({nd, to});\n                } else if (parE && nd == dist[to]) {\n                    if ((*parE)[to] == -1 || id < (*parE)[to]) {\n                        (*parV)[to] = v;\n                        (*parE)[to] = id;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> choose_landmarks(int L) {\n        L = min(L, N);\n        vector<int> res;\n        res.reserve(L);\n\n        auto dist2 = [&](int a, int b) -> ll {\n            ll dx = coord[a].first - coord[b].first;\n            ll dy = coord[a].second - coord[b].second;\n            return dx * dx + dy * dy;\n        };\n\n        vector<ll> best(N, (1LL << 62));\n        int first = 0;\n        res.push_back(first);\n        for (int i = 0; i < N; i++) best[i] = dist2(i, first);\n\n        while ((int)res.size() < L) {\n            int cand = -1;\n            ll mx = -1;\n            for (int i = 0; i < N; i++) {\n                if (best[i] > mx) {\n                    mx = best[i];\n                    cand = i;\n                }\n            }\n            res.push_back(cand);\n            for (int i = 0; i < N; i++) best[i] = min(best[i], dist2(i, cand));\n        }\n        return res;\n    }\n\n    void compute_importance() {\n        landmarks = choose_landmarks(L_imp);\n        L_imp = (int)landmarks.size();\n        L_eval = min(L_eval, L_imp);\n        origEvalDist.assign(L_eval, vector<ll>(N, INF64));\n\n        vector<ll> dist;\n        vector<int> parV, parE;\n\n        for (int li = 0; li < L_imp; li++) {\n            int s = landmarks[li];\n            dijkstra_full(s, dist, -1, -1, -1, &parV, &parE);\n\n            if (li < L_eval) origEvalDist[li] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sz(N, 1);\n            for (int v : ord) {\n                if (v == s) continue;\n                int pe = parE[v];\n                int pv = parV[v];\n                if (pe >= 0) {\n                    edges[pe].usage += sz[v];\n                    sz[pv] += sz[v];\n                }\n            }\n        }\n\n        vector<ll> dist2;\n        for (int eid = 0; eid < M; eid++) {\n            int s = edges[eid].u;\n            int t = edges[eid].v;\n            dijkstra_full(s, dist2, eid, -1, t, nullptr, nullptr);\n            ll alt = dist2[t];\n            if (alt >= INF64 / 2) alt = (ll)1e18;\n            edges[eid].detour = max<ll>(0, alt - edges[eid].w);\n        }\n\n        double avgUsage = 0.0, avgDet = 0.0;\n        for (int i = 0; i < M; i++) {\n            avgUsage += edges[i].usage + 1.0;\n            avgDet += (double)edges[i].detour + 1.0;\n        }\n        avgUsage /= M;\n        avgDet /= M;\n\n        vector<double> raw(M);\n        double meanRaw = 0.0;\n        for (int i = 0; i < M; i++) {\n            double u = (edges[i].usage + 1.0) / avgUsage;\n            double d = ((double)edges[i].detour + 1.0) / avgDet;\n            raw[i] = u * d;\n            meanRaw += raw[i];\n        }\n        meanRaw /= M;\n        if (meanRaw <= 0) meanRaw = 1.0;\n\n        for (int i = 0; i < M; i++) {\n            edges[i].imp = raw[i] / meanRaw;\n        }\n    }\n\n    void compute_two_edge_cut_conflicts() {\n        vector<int> tin(N), low(N);\n        int timer = 0;\n\n        function<void(int,int,int, vector<int>&)> dfs = [&](int v, int pe, int banned, vector<int> &bridges) {\n            tin[v] = low[v] = timer++;\n            for (const auto &ad : g[v]) {\n                int id = ad.id;\n                if (id == banned) continue;\n                if (id == pe) continue;\n                int to = ad.to;\n                if (tin[to] != -1) {\n                    low[v] = min(low[v], tin[to]);\n                } else {\n                    dfs(to, id, banned, bridges);\n                    low[v] = min(low[v], low[to]);\n                    if (low[to] > tin[v]) bridges.push_back(id);\n                }\n            }\n        };\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), -1);\n            fill(low.begin(), low.end(), -1);\n            timer = 0;\n            vector<int> bridges;\n            for (int s = 0; s < N; s++) {\n                if (tin[s] == -1) dfs(s, -1, banned, bridges);\n            }\n            for (int f : bridges) {\n                if (f > banned) add_conflict(banned, f);\n            }\n        }\n    }\n\n    inline bool touches(int eid, int v) const {\n        return edges[eid].u == v || edges[eid].v == v;\n    }\n\n    void clear_assignment() {\n        fill(dayOf.begin(), dayOf.end(), -1);\n        fill(posInDay.begin(), posInDay.end(), -1);\n        dayEdges.assign(D, {});\n        fill(dayCnt.begin(), dayCnt.end(), 0);\n        fill(dayLoad.begin(), dayLoad.end(), 0.0);\n        for (auto &a : cntV) a.fill(0);\n        for (auto &a : cntCell) a.fill(0);\n        for (auto &a : confCnt) a.fill(0);\n        dayScore.clear();\n    }\n\n    void add_edge_to_day(int eid, int d) {\n        dayOf[eid] = d;\n        posInDay[eid] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(eid);\n\n        dayCnt[d]++;\n        dayLoad[d] += edges[eid].imp;\n\n        cntV[edges[eid].u][d]++;\n        cntV[edges[eid].v][d]++;\n        cntCell[edges[eid].cell][d]++;\n\n        for (int f : conflicts[eid]) confCnt[f][d]++;\n    }\n\n    void remove_edge_from_day(int eid, int d) {\n        int pos = posInDay[eid];\n        int last = dayEdges[d].back();\n        dayEdges[d][pos] = last;\n        posInDay[last] = pos;\n        dayEdges[d].pop_back();\n\n        dayCnt[d]--;\n        dayLoad[d] -= edges[eid].imp;\n\n        cntV[edges[eid].u][d]--;\n        cntV[edges[eid].v][d]--;\n        cntCell[edges[eid].cell][d]--;\n\n        for (int f : conflicts[eid]) confCnt[f][d]--;\n\n        dayOf[eid] = -1;\n        posInDay[eid] = -1;\n    }\n\n    void move_edge_day(int eid, int nd) {\n        int od = dayOf[eid];\n        if (od == nd) return;\n        remove_edge_from_day(eid, od);\n        add_edge_to_day(eid, nd);\n    }\n\n    void rebuild_from_assignment(const vector<int> &assign) {\n        clear_assignment();\n        for (int e = 0; e < M; e++) add_edge_to_day(e, assign[e]);\n    }\n\n    inline bool feasible_add_strict(int eid, int d) const {\n        if (dayCnt[d] >= K) return false;\n        if (confCnt[eid][d] > 0) return false;\n        const auto &e = edges[eid];\n        if (cntV[e.u][d] + 1 >= degv[e.u]) return false;\n        if (cntV[e.v][d] + 1 >= degv[e.v]) return false;\n        return true;\n    }\n\n    inline bool feasible_add_relaxed_vertex(int eid, int d) const {\n        if (dayCnt[d] >= K) return false;\n        if (confCnt[eid][d] > 0) return false;\n        return true;\n    }\n\n    inline double greedy_add_cost(int eid, int d) const {\n        const auto &e = edges[eid];\n        double x = e.imp;\n        double cost = 0.0;\n        cost += WA * (2.0 * dayLoad[d] * x + x * x);\n        cost += WB * (cntV[e.u][d] * vCoef[e.u] + cntV[e.v][d] * vCoef[e.v]);\n        cost += WC * cntCell[e.cell][d];\n        cost += WQ * (2.0 * dayCnt[d] + 1.0);\n        return cost;\n    }\n\n    void build_initial_solution_variant(int variant) {\n        clear_assignment();\n\n        double alpha = 0.14 + 0.04 * (variant % 3);\n        double noiseAmp = 0.015 + 0.015 * (variant % 2);\n\n        vector<pair<double,int>> ord;\n        ord.reserve(M);\n        uniform_real_distribution<double> ur(-noiseAmp, noiseAmp);\n        for (int i = 0; i < M; i++) {\n            double lowDegBonus = 1.0 + 0.20 * (vCoef[edges[i].u] + vCoef[edges[i].v]);\n            double base = edges[i].imp * lowDegBonus * (1.0 + alpha * sqrt((double)conflicts[i].size() + 1.0));\n            base *= (1.0 + ur(rng));\n            ord.push_back({base, i});\n        }\n        sort(ord.begin(), ord.end(), [&](auto &a, auto &b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        vector<int> days(D);\n        iota(days.begin(), days.end(), 0);\n\n        for (auto &[_, eid] : ord) {\n            shuffle(days.begin(), days.end(), rng);\n\n            double bestCost = 1e100;\n            int bestDay = -1;\n\n            for (int d : days) {\n                if (!feasible_add_strict(eid, d)) continue;\n                double c = greedy_add_cost(eid, d);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestDay = d;\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (!feasible_add_relaxed_vertex(eid, d)) continue;\n                    double c = greedy_add_cost(eid, d) + 1e5;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d : days) {\n                    if (dayCnt[d] >= K) continue;\n                    const auto &e = edges[eid];\n                    double c = greedy_add_cost(eid, d);\n                    c += 1e7 * confCnt[eid][d];\n                    if (cntV[e.u][d] + 1 >= degv[e.u]) c += 1e6;\n                    if (cntV[e.v][d] + 1 >= degv[e.v]) c += 1e6;\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestDay = d;\n                    }\n                }\n            }\n\n            if (bestDay == -1) {\n                for (int d = 0; d < D; d++) {\n                    if (dayCnt[d] < K) {\n                        bestDay = d;\n                        break;\n                    }\n                }\n            }\n\n            add_edge_to_day(eid, bestDay);\n        }\n    }\n\n    bool day_connected(int blockedDay, vector<int> *compOut = nullptr) {\n        vector<int> comp(N, -1);\n        queue<int> q;\n        int cc = 0;\n\n        for (int s = 0; s < N; s++) {\n            if (comp[s] != -1) continue;\n            comp[s] = cc;\n            q.push(s);\n            while (!q.empty()) {\n                int v = q.front();\n                q.pop();\n                for (const auto &ad : g[v]) {\n                    if (dayOf[ad.id] == blockedDay) continue;\n                    int to = ad.to;\n                    if (comp[to] == -1) {\n                        comp[to] = cc;\n                        q.push(to);\n                    }\n                }\n            }\n            cc++;\n            if (!compOut && cc >= 2) return false;\n        }\n\n        if (compOut) *compOut = move(comp);\n        return cc == 1;\n    }\n\n    struct InitMetric {\n        int badConn;\n        ll badConflict;\n        int badVertex;\n        double proxy;\n    };\n\n    InitMetric evaluate_current_assignment() {\n        int badConn = 0;\n        for (int d = 0; d < D; d++) {\n            if (!day_connected(d)) badConn++;\n        }\n\n        ll badConflict = 0;\n        for (int e = 0; e < M; e++) badConflict += confCnt[e][dayOf[e]];\n        badConflict /= 2;\n\n        int badVertex = 0;\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) {\n                if (cntV[v][d] >= degv[v]) badVertex++;\n            }\n        }\n\n        double proxy = 0.0;\n        for (int d = 0; d < D; d++) {\n            proxy += WA * dayLoad[d] * dayLoad[d];\n            proxy += WQ * dayCnt[d] * dayCnt[d];\n        }\n        for (int v = 0; v < N; v++) {\n            for (int d = 0; d < D; d++) proxy += WB * vCoef[v] * comb2(cntV[v][d]);\n        }\n        for (int c = 0; c < C; c++) {\n            for (int d = 0; d < D; d++) proxy += WC * comb2(cntCell[c][d]);\n        }\n\n        return {badConn, badConflict, badVertex, proxy};\n    }\n\n    bool better_metric(const InitMetric &a, const InitMetric &b) {\n        if (a.badConn != b.badConn) return a.badConn < b.badConn;\n        if (a.badConflict != b.badConflict) return a.badConflict < b.badConflict;\n        if (a.badVertex != b.badVertex) return a.badVertex < b.badVertex;\n        return a.proxy < b.proxy;\n    }\n\n    void multi_start_initial_solution() {\n        vector<int> bestAssign;\n        InitMetric bestMet{INT_MAX, (ll)4e18, INT_MAX, 1e100};\n\n        int tries = 0;\n        while (tries < 5 && elapsed() < 1.20) {\n            build_initial_solution_variant(tries);\n            InitMetric met = evaluate_current_assignment();\n            if (bestAssign.empty() || better_metric(met, bestMet)) {\n                bestAssign = dayOf;\n                bestMet = met;\n            }\n            tries++;\n        }\n\n        if (bestAssign.empty()) build_initial_solution_variant(0);\n        else rebuild_from_assignment(bestAssign);\n    }\n\n    inline bool valid_swap_hard(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return false;\n\n        int ic = is_conflict(e1, e2) ? 1 : 0;\n        if (confCnt[e1][b] - ic > 0) return false;\n        if (confCnt[e2][a] - ic > 0) return false;\n\n        int vs[4] = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs, vs + 4);\n        int m = unique(vs, vs + 4) - vs;\n\n        for (int i = 0; i < m; i++) {\n            int v = vs[i];\n            int cntA = cntV[v][a];\n            int cntB = cntV[v][b];\n            int newA = cntA - (touches(e1, v) ? 1 : 0) + (touches(e2, v) ? 1 : 0);\n            int newB = cntB - (touches(e2, v) ? 1 : 0) + (touches(e1, v) ? 1 : 0);\n            if (newA >= degv[v]) return false;\n            if (newB >= degv[v]) return false;\n        }\n        return true;\n    }\n\n    inline bool valid_move_hard(int e, int toDay) const {\n        int fromDay = dayOf[e];\n        if (fromDay == toDay) return false;\n        if (dayCnt[toDay] >= K) return false;\n        if (confCnt[e][toDay] > 0) return false;\n\n        const auto &E = edges[e];\n        if (cntV[E.u][toDay] + 1 >= degv[E.u]) return false;\n        if (cntV[E.v][toDay] + 1 >= degv[E.v]) return false;\n        return true;\n    }\n\n    double proxy_swap_delta(int e1, int e2) const {\n        int a = dayOf[e1], b = dayOf[e2];\n        if (a == b) return 0.0;\n\n        const auto &E1 = edges[e1];\n        const auto &E2 = edges[e2];\n        double delta = 0.0;\n\n        {\n            double la = dayLoad[a], lb = dayLoad[b];\n            double x = E1.imp, y = E2.imp;\n            double nla = la - x + y;\n            double nlb = lb - y + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n\n        {\n            int vs[4] = {E1.u, E1.v, E2.u, E2.v};\n            sort(vs, vs + 4);\n            int m = unique(vs, vs + 4) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][a];\n                int cb = cntV[v][b];\n                int da = 0;\n                if (touches(e1, v)) da--;\n                if (touches(e2, v)) da++;\n                int db = -da;\n                add += vCoef[v] * (comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb));\n            }\n            delta += WB * add;\n        }\n\n        {\n            int cs[2] = {E1.cell, E2.cell};\n            sort(cs, cs + 2);\n            int m = unique(cs, cs + 2) - cs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int c = cs[i];\n                int ca = cntCell[c][a];\n                int cb = cntCell[c][b];\n                int da = 0;\n                if (E1.cell == c) da--;\n                if (E2.cell == c) da++;\n                int db = -da;\n                add += comb2(ca + da) + comb2(cb + db) - comb2(ca) - comb2(cb);\n            }\n            delta += WC * add;\n        }\n\n        return delta;\n    }\n\n    double proxy_move_delta(int e, int toDay) const {\n        int fromDay = dayOf[e];\n        if (fromDay == toDay) return 0.0;\n\n        const auto &E = edges[e];\n        double x = E.imp;\n        double delta = 0.0;\n\n        {\n            double la = dayLoad[fromDay], lb = dayLoad[toDay];\n            double nla = la - x;\n            double nlb = lb + x;\n            delta += WA * (nla * nla + nlb * nlb - la * la - lb * lb);\n        }\n        {\n            double ca = dayCnt[fromDay], cb = dayCnt[toDay];\n            double nca = ca - 1, ncb = cb + 1;\n            delta += WQ * (nca * nca + ncb * ncb - ca * ca - cb * cb);\n        }\n        {\n            int vs[2] = {E.u, E.v};\n            sort(vs, vs + 2);\n            int m = unique(vs, vs + 2) - vs;\n            double add = 0.0;\n            for (int i = 0; i < m; i++) {\n                int v = vs[i];\n                int ca = cntV[v][fromDay];\n                int cb = cntV[v][toDay];\n                add += vCoef[v] * (comb2(ca - 1) + comb2(cb + 1) - comb2(ca) - comb2(cb));\n            }\n            delta += WB * add;\n        }\n        {\n            int c = E.cell;\n            int ca = cntCell[c][fromDay];\n            int cb = cntCell[c][toDay];\n            delta += WC * (comb2(ca - 1) + comb2(cb + 1) - comb2(ca) - comb2(cb));\n        }\n\n        return delta;\n    }\n\n    void apply_swap(int e1, int e2) {\n        int d1 = dayOf[e1], d2 = dayOf[e2];\n        if (d1 == d2) return;\n        remove_edge_from_day(e1, d1);\n        remove_edge_from_day(e2, d2);\n        add_edge_to_day(e1, d2);\n        add_edge_to_day(e2, d1);\n    }\n\n    void apply_move(int e, int toDay) {\n        move_edge_day(e, toDay);\n    }\n\n    double edge_badness_in_day(int e, int d) const {\n        const auto &E = edges[e];\n        double s = E.imp;\n        s += 0.90 * max(0, cntV[E.u][d] - 1) * vCoef[E.u];\n        s += 0.90 * max(0, cntV[E.v][d] - 1) * vCoef[E.v];\n        s += 0.10 * cntCell[E.cell][d];\n        s += 0.02 * sqrt((double)conflicts[e].size() + 1.0);\n        return s;\n    }\n\n    int pick_edge_from_day(int d, bool highBad) {\n        const auto &vec = dayEdges[d];\n        int sz = (int)vec.size();\n        if (sz == 0) return -1;\n\n        int best = vec[rng() % sz];\n        double bestScore = edge_badness_in_day(best, d);\n\n        int trials = min(sz, 8);\n        for (int t = 1; t < trials; t++) {\n            int cand = vec[rng() % sz];\n            double sc = edge_badness_in_day(cand, d);\n            if (highBad) {\n                if (sc > bestScore || (sc == bestScore && edges[cand].imp > edges[best].imp)) {\n                    best = cand;\n                    bestScore = sc;\n                }\n            } else {\n                if (sc < bestScore || (sc == bestScore && edges[cand].imp < edges[best].imp)) {\n                    best = cand;\n                    bestScore = sc;\n                }\n            }\n        }\n        return best;\n    }\n\n    void repair_connectivity(double timeLimit) {\n        vector<int> comp;\n        while (elapsed() < timeLimit) {\n            int badDay = -1;\n            for (int d = 0; d < D; d++) {\n                if (!day_connected(d)) {\n                    badDay = d;\n                    break;\n                }\n            }\n            if (badDay == -1) break;\n\n            day_connected(badDay, &comp);\n\n            vector<int> candE;\n            candE.reserve(dayEdges[badDay].size());\n            for (int e : dayEdges[badDay]) {\n                if (comp[edges[e].u] != comp[edges[e].v]) candE.push_back(e);\n            }\n            if (candE.empty()) candE = dayEdges[badDay];\n\n            sort(candE.begin(), candE.end(), [&](int a, int b) {\n                double sa = edge_badness_in_day(a, badDay);\n                double sb = edge_badness_in_day(b, badDay);\n                if (sa != sb) return sa > sb;\n                return a < b;\n            });\n\n            bool improved = false;\n\n            // 1) relocate first\n            {\n                double bestDelta = 1e100;\n                int bestE = -1, bestTo = -1;\n\n                int limE = min((int)candE.size(), 30);\n                vector<int> dayOrd(D);\n                iota(dayOrd.begin(), dayOrd.end(), 0);\n                sort(dayOrd.begin(), dayOrd.end(), [&](int x, int y) {\n                    if (dayCnt[x] != dayCnt[y]) return dayCnt[x] < dayCnt[y];\n                    return dayLoad[x] < dayLoad[y];\n                });\n\n                for (int ii = 0; ii < limE && elapsed() < timeLimit; ii++) {\n                    int e = candE[ii];\n                    for (int t = 0; t < D && elapsed() < timeLimit; t++) {\n                        int d2 = dayOrd[t];\n                        if (d2 == badDay) continue;\n                        if (!valid_move_hard(e, d2)) continue;\n\n                        double delta = proxy_move_delta(e, d2);\n                        int old = dayOf[e];\n                        apply_move(e, d2);\n                        bool ok2 = day_connected(d2);\n                        bool ok1 = day_connected(badDay);\n                        apply_move(e, old);\n\n                        if (ok1 && ok2 && delta < bestDelta) {\n                            bestDelta = delta;\n                            bestE = e;\n                            bestTo = d2;\n                        }\n                    }\n                }\n\n                if (bestE != -1) {\n                    apply_move(bestE, bestTo);\n                    improved = true;\n                }\n            }\n            if (improved) continue;\n\n            // 2) swap fallback\n            {\n                double bestDelta = 1e100;\n                int bestE = -1, bestF = -1;\n\n                int limE = min((int)candE.size(), 25);\n                for (int ii = 0; ii < limE && elapsed() < timeLimit; ii++) {\n                    int e = candE[ii];\n                    for (int d2 = 0; d2 < D && elapsed() < timeLimit; d2++) {\n                        if (d2 == badDay || dayEdges[d2].empty()) continue;\n\n                        auto &vec = dayEdges[d2];\n                        vector<int> trialF;\n                        int sample = min((int)vec.size(), 16);\n                        for (int t = 0; t < sample; t++) trialF.push_back(vec[rng() % vec.size()]);\n                        trialF.push_back(vec[0]);\n                        trialF.push_back(vec.back());\n                        sort(trialF.begin(), trialF.end());\n                        trialF.erase(unique(trialF.begin(), trialF.end()), trialF.end());\n\n                        for (int f : trialF) {\n                            if (!valid_swap_hard(e, f)) continue;\n                            double delta = proxy_swap_delta(e, f);\n                            if (delta > bestDelta + 5.0) continue;\n\n                            apply_swap(e, f);\n                            bool ok1 = day_connected(badDay);\n                            bool ok2 = day_connected(d2);\n                            apply_swap(e, f);\n\n                            if (ok1 && ok2 && delta < bestDelta) {\n                                bestDelta = delta;\n                                bestE = e;\n                                bestF = f;\n                            }\n                        }\n                    }\n                }\n\n                if (bestE != -1) {\n                    apply_swap(bestE, bestF);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    void proxy_local_search(double timeLimit) {\n        while (elapsed() < timeLimit) {\n            if ((rng() & 1) == 0) {\n                int a = rng() % D;\n                int b = rng() % D;\n                if (a == b) continue;\n                if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n                if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n                int e1 = pick_edge_from_day(a, true);\n                int e2 = pick_edge_from_day(b, false);\n                if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n                if (!valid_swap_hard(e1, e2)) continue;\n\n                double delta = proxy_swap_delta(e1, e2);\n                if (delta < 0.0) apply_swap(e1, e2);\n            } else {\n                int a = rng() % D;\n                int b = rng() % D;\n                if (a == b) continue;\n                if (dayEdges[a].empty()) continue;\n                if (dayLoad[a] < dayLoad[b]) swap(a, b);\n\n                int e = pick_edge_from_day(a, true);\n                if (e < 0) continue;\n                if (!valid_move_hard(e, b)) continue;\n\n                double delta = proxy_move_delta(e, b);\n                if (delta < -0.10) {\n                    int old = dayOf[e];\n                    apply_move(e, b);\n                    if (!day_connected(b)) apply_move(e, old);\n                }\n            }\n        }\n    }\n\n    ll eval_day_score(int blockedDay) {\n        vector<ll> dist;\n        ll total = 0;\n        for (int si = 0; si < L_eval; si++) {\n            dijkstra_full(landmarks[si], dist, -1, blockedDay, -1, nullptr, nullptr);\n            for (int v = 0; v < N; v++) {\n                ll dv = (dist[v] >= INF64 / 2 ? (ll)1e9 : dist[v]);\n                total += dv - origEvalDist[si][v];\n            }\n        }\n        return total;\n    }\n\n    void init_day_scores() {\n        dayScore.assign(D, 0);\n        for (int d = 0; d < D; d++) dayScore[d] = eval_day_score(d);\n    }\n\n    void sampled_local_search(double timeLimit) {\n        if (dayScore.empty()) init_day_scores();\n\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n\n        int evalCnt = 0;\n        const int MAX_EVAL = 220;\n\n        while (elapsed() < timeLimit && evalCnt < MAX_EVAL) {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dayScore[a] > dayScore[b];\n            });\n\n            if ((rng() & 1) == 0) {\n                int topk = min(5, D);\n                int botk = min(6, D);\n                int a = ord[rng() % topk];\n\n                vector<int> targets;\n                for (int i = 0; i < botk; i++) {\n                    int b = ord[D - 1 - i];\n                    if (b != a && dayCnt[b] < K) targets.push_back(b);\n                }\n                if (targets.empty()) continue;\n                int b = targets[rng() % targets.size()];\n\n                if (dayEdges[a].empty()) continue;\n                int e = pick_edge_from_day(a, true);\n                if (e < 0) continue;\n                if (!valid_move_hard(e, b)) continue;\n\n                double pdelta = proxy_move_delta(e, b);\n                if (pdelta > 2.0 && (rng() & 3)) continue;\n\n                int old = dayOf[e];\n                apply_move(e, b);\n\n                if (!day_connected(b)) {\n                    apply_move(e, old);\n                    continue;\n                }\n\n                ll na = eval_day_score(a);\n                ll nb = eval_day_score(b);\n                evalCnt++;\n\n                ll oldScore = dayScore[a] + dayScore[b];\n                ll newScore = na + nb;\n\n                if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                    dayScore[a] = na;\n                    dayScore[b] = nb;\n                } else {\n                    apply_move(e, old);\n                }\n            } else {\n                int topk = min(5, D);\n                int botk = min(5, D);\n                int a = ord[rng() % topk];\n                int b = ord[D - 1 - (rng() % botk)];\n                if (a == b) continue;\n                if (dayEdges[a].empty() || dayEdges[b].empty()) continue;\n\n                int e1 = pick_edge_from_day(a, true);\n                int e2 = pick_edge_from_day(b, false);\n                if (e1 < 0 || e2 < 0 || e1 == e2) continue;\n                if (!valid_swap_hard(e1, e2)) continue;\n\n                double pdelta = proxy_swap_delta(e1, e2);\n                if (pdelta > 3.0 && (rng() & 3)) continue;\n\n                apply_swap(e1, e2);\n\n                if (!day_connected(a) || !day_connected(b)) {\n                    apply_swap(e1, e2);\n                    continue;\n                }\n\n                ll na = eval_day_score(a);\n                ll nb = eval_day_score(b);\n                evalCnt++;\n\n                ll oldScore = dayScore[a] + dayScore[b];\n                ll newScore = na + nb;\n\n                if (newScore < oldScore || (newScore == oldScore && pdelta < 0.0)) {\n                    dayScore[a] = na;\n                    dayScore[b] = nb;\n                } else {\n                    apply_swap(e1, e2);\n                }\n            }\n        }\n    }\n\n    void solve() {\n        read_input();\n        compute_two_edge_cut_conflicts();\n        compute_importance();\n\n        multi_start_initial_solution();\n\n        if (elapsed() < 1.8) repair_connectivity(1.8);\n        if (elapsed() < 3.0) proxy_local_search(3.0);\n        if (elapsed() < 4.0) repair_connectivity(4.0);\n        if (elapsed() < 5.90) sampled_local_search(5.90);\n        if (elapsed() < 5.98) repair_connectivity(5.98);\n    }\n\n    void output() {\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << (dayOf[i] + 1);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> g;\n    vector<int> dist, pairU, pairV;\n\n    HopcroftKarp(int nL = 0, int nR = 0) : nL(nL), nR(nR), g(nL) {}\n\n    void add_edge(int u, int v) { g[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        bool found = false;\n        for (int u = 0; u < nL; ++u) {\n            if (pairU[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : g[u]) {\n                int pu = pairV[v];\n                if (pu == -1) {\n                    found = true;\n                } else if (dist[pu] == -1) {\n                    dist[pu] = dist[u] + 1;\n                    q.push(pu);\n                }\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for (int v : g[u]) {\n            int pu = pairV[v];\n            if (pu == -1 || (dist[pu] == dist[u] + 1 && dfs(pu))) {\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\nstruct ObjData {\n    int D;\n    vector<string> f, r;\n    vector<vector<int>> Xs, Ys;\n    vector<int> Xmask, Ymask;\n};\n\nstruct OccCandidate {\n    vector<char> occ;\n    int V = 0;\n    string name;\n};\n\nstruct AnalysisResult {\n    int V = 0;\n    vector<int> occLins;\n    vector<pair<int,int>> doms;\n};\n\nstruct LayerState {\n    vector<int> cells2;\n};\n\nstruct Block {\n    int size;\n    int sig;\n    vector<int> cells;\n};\n\nstruct Partition {\n    int V = 0;\n    string name;\n    vector<Block> blocks;\n    unordered_map<int, vector<int>> bySig;\n    vector<pair<int,int>> sigCounts;\n};\n\nstruct PartitionSpec {\n    string name;\n    vector<int> ops;\n    vector<int> lens;\n    array<int,3> axisRank;\n};\n\nstruct Solver {\n    int D;\n    ObjData obj[2];\n\n    vector<array<int,6>> rots;\n    unordered_map<string, int> sigId;\n    vector<int> sigSize;\n\n    Solver(int D) : D(D) {\n        init_rotations();\n    }\n\n    int lin(int x, int y, int z) const {\n        return x * D * D + y * D + z;\n    }\n\n    tuple<int,int,int> invlin(int id) const {\n        int z = id % D;\n        id /= D;\n        int y = id % D;\n        int x = id / D;\n        return {x, y, z};\n    }\n\n    int lin2(int x, int y) const {\n        return x * D + y;\n    }\n\n    static int popcnt(int x) {\n        return __builtin_popcount((unsigned)x);\n    }\n\n    void prepare_obj(int idx, const vector<string>& f, const vector<string>& r) {\n        obj[idx].D = D;\n        obj[idx].f = f;\n        obj[idx].r = r;\n        obj[idx].Xs.assign(D, {});\n        obj[idx].Ys.assign(D, {});\n        obj[idx].Xmask.assign(D, 0);\n        obj[idx].Ymask.assign(D, 0);\n\n        for (int z = 0; z < D; ++z) {\n            for (int x = 0; x < D; ++x) {\n                if (f[z][x] == '1') {\n                    obj[idx].Xs[z].push_back(x);\n                    obj[idx].Xmask[z] |= (1 << x);\n                }\n            }\n            for (int y = 0; y < D; ++y) {\n                if (r[z][y] == '1') {\n                    obj[idx].Ys[z].push_back(y);\n                    obj[idx].Ymask[z] |= (1 << y);\n                }\n            }\n        }\n    }\n\n    int perm_parity(const array<int,3>& p) const {\n        int inv = 0;\n        for (int i = 0; i < 3; ++i) for (int j = i + 1; j < 3; ++j) {\n            if (p[i] > p[j]) ++inv;\n        }\n        return (inv % 2 == 0 ? 1 : -1);\n    }\n\n    void init_rotations() {\n        array<int,3> p = {0, 1, 2};\n        do {\n            int pp = perm_parity(p);\n            for (int s0 : {-1, 1}) for (int s1 : {-1, 1}) for (int s2 : {-1, 1}) {\n                if (pp * s0 * s1 * s2 == 1) {\n                    rots.push_back({p[0], p[1], p[2], s0, s1, s2});\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    int canonical_id(const vector<int>& cells) {\n        vector<array<int,3>> pts;\n        pts.reserve(cells.size());\n        for (int id : cells) {\n            auto [x,y,z] = invlin(id);\n            pts.push_back({x,y,z});\n        }\n\n        string best;\n        bool first = true;\n\n        for (auto rt : rots) {\n            vector<array<int,3>> q;\n            q.reserve(pts.size());\n            int mnx = INT_MAX, mny = INT_MAX, mnz = INT_MAX;\n\n            for (auto c : pts) {\n                int a[3] = {c[0], c[1], c[2]};\n                int nx = rt[3] * a[rt[0]];\n                int ny = rt[4] * a[rt[1]];\n                int nz = rt[5] * a[rt[2]];\n                q.push_back({nx, ny, nz});\n                mnx = min(mnx, nx);\n                mny = min(mny, ny);\n                mnz = min(mnz, nz);\n            }\n\n            for (auto &v : q) {\n                v[0] -= mnx;\n                v[1] -= mny;\n                v[2] -= mnz;\n            }\n            sort(q.begin(), q.end());\n\n            string s;\n            s.reserve(q.size() * 8);\n            for (auto v : q) {\n                s += to_string(v[0]);\n                s += ',';\n                s += to_string(v[1]);\n                s += ',';\n                s += to_string(v[2]);\n                s += ';';\n            }\n            if (first || s < best) {\n                first = false;\n                best = move(s);\n            }\n        }\n\n        auto it = sigId.find(best);\n        if (it != sigId.end()) return it->second;\n        int id = (int)sigSize.size();\n        sigId.emplace(best, id);\n        sigSize.push_back((int)cells.size());\n        return id;\n    }\n\n    AnalysisResult analyze_occ_for_domino(const vector<char>& occ) const {\n        AnalysisResult res;\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!occ[id]) continue;\n            res.occLins.push_back(id);\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) {\n                res.doms.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n            }\n        }\n        res.V = (int)res.occLins.size();\n        return res;\n    }\n\n    vector<char> build_cross_occ(const ObjData& o, const vector<pair<int,int>>& centers) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            int cx = centers[z].first;\n            int cy = centers[z].second;\n            for (int x : o.Xs[z]) occ[lin(x, cy, z)] = 1;\n            for (int y : o.Ys[z]) occ[lin(cx, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    int cross_transition_score(const ObjData& o, int z, pair<int,int> a, pair<int,int> b) const {\n        int xcap = popcnt(o.Xmask[z] & o.Xmask[z+1]);\n        int ycap = popcnt(o.Ymask[z] & o.Ymask[z+1]);\n        int s = 0;\n        if (a.second == b.second) s += xcap;\n        if (a.first  == b.first ) s += ycap;\n        if (a.first == b.first && a.second == b.second) s -= 1;\n        return s;\n    }\n\n    vector<vector<pair<int,int>>> make_cross_states(const ObjData& o) const {\n        vector<vector<pair<int,int>>> states(D);\n        for (int z = 0; z < D; ++z) {\n            for (int x : o.Xs[z]) for (int y : o.Ys[z]) states[z].push_back({x, y});\n        }\n        return states;\n    }\n\n    vector<vector<int>> cross_dp_scores(const ObjData& o, const vector<vector<pair<int,int>>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1000000000);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int cand = dp[z-1][i] + cross_transition_score(o, z - 1, states[z - 1][i], states[z][j]);\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    vector<pair<int,int>> reconstruct_cross_path(const vector<vector<pair<int,int>>>& states, const vector<vector<int>>& prv, int lastIdx) const {\n        vector<pair<int,int>> centers(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            centers[z] = states[z][cur];\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n        return centers;\n    }\n\n    int local_overlap_score_cross(const ObjData& o, const vector<pair<int,int>>& centers, int z, pair<int,int> cand) const {\n        int s = 0;\n        if (z > 0) s += cross_transition_score(o, z - 1, centers[z - 1], cand);\n        if (z + 1 < D) s += cross_transition_score(o, z, cand, centers[z + 1]);\n        return s;\n    }\n\n    OccCandidate build_cross_local_from_centers(const ObjData& o, vector<pair<int,int>> centers, const string& name) const {\n        auto bestOcc = build_cross_occ(o, centers);\n        auto bestAna = analyze_occ_for_domino(bestOcc);\n\n        bool improved = true;\n        for (int pass = 0; pass < 2 && improved; ++pass) {\n            improved = false;\n            for (int z = 0; z < D; ++z) {\n                auto curCenter = centers[z];\n                int curMatch = (int)bestAna.doms.size();\n                int curTie = local_overlap_score_cross(o, centers, z, curCenter);\n\n                auto bestCenter = curCenter;\n                auto bestOccHere = bestOcc;\n                auto bestAnaHere = bestAna;\n                int bestMatch = curMatch;\n                int bestTie = curTie;\n\n                for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                    pair<int,int> cand = {x, y};\n                    if (cand == curCenter) continue;\n                    centers[z] = cand;\n                    auto occ = build_cross_occ(o, centers);\n                    auto ana = analyze_occ_for_domino(occ);\n                    int m = (int)ana.doms.size();\n                    int tie = local_overlap_score_cross(o, centers, z, cand);\n                    if (m > bestMatch || (m == bestMatch && tie > bestTie)) {\n                        bestMatch = m;\n                        bestTie = tie;\n                        bestCenter = cand;\n                        bestOccHere = move(occ);\n                        bestAnaHere = move(ana);\n                    }\n                }\n\n                centers[z] = bestCenter;\n                if (bestCenter != curCenter) {\n                    bestOcc = move(bestOccHere);\n                    bestAna = move(bestAnaHere);\n                    if (bestMatch > curMatch) improved = true;\n                }\n            }\n        }\n\n        return {move(bestOcc), bestAna.V, name};\n    }\n\n    vector<OccCandidate> build_cross_candidates(const ObjData& o, const string& baseName, int topK = 4) const {\n        vector<OccCandidate> res;\n        auto states = make_cross_states(o);\n        vector<vector<int>> prv;\n        auto dp = cross_dp_scores(o, states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n        for (int t = 0; t < topK; ++t) {\n            auto centers = reconstruct_cross_path(states, prv, ord[t]);\n            OccCandidate c;\n            c.occ = build_cross_occ(o, centers);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = baseName + \"_dp\" + to_string(t);\n            res.push_back(move(c));\n        }\n\n        if (!ord.empty()) {\n            auto centers = reconstruct_cross_path(states, prv, ord[0]);\n            res.push_back(build_cross_local_from_centers(o, centers, baseName + \"_local\"));\n        }\n        return res;\n    }\n\n    vector<char> build_min_occ(const ObjData& o, bool rev) const {\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            auto X = o.Xs[z];\n            auto Y = o.Ys[z];\n            int a = (int)X.size();\n            int b = (int)Y.size();\n\n            if (a >= b) {\n                if (rev) reverse(Y.begin(), Y.end());\n                for (int j = 0; j < b; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = b; j < a; ++j) occ[lin(X[j], Y[0], z)] = 1;\n            } else {\n                if (rev) reverse(X.begin(), X.end());\n                for (int j = 0; j < a; ++j) occ[lin(X[j], Y[j], z)] = 1;\n                for (int j = a; j < b; ++j) occ[lin(X[0], Y[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    vector<int> build_star_layer_cells(const ObjData& o, int z, bool anchorOnY, int anchorVal, bool rev, int offset) const {\n        vector<int> res;\n        auto X = o.Xs[z];\n        auto Y = o.Ys[z];\n        sort(X.begin(), X.end());\n        sort(Y.begin(), Y.end());\n\n        if (anchorOnY) {\n            int y0 = anchorVal;\n            vector<int> otherY;\n            for (int y : Y) if (y != y0) otherY.push_back(y);\n            if (rev) reverse(otherY.begin(), otherY.end());\n\n            int a = (int)X.size();\n            int k = (int)otherY.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int x = X[(offset + i) % a];\n                mp[x] = otherY[i];\n            }\n            for (int x : X) {\n                auto it = mp.find(x);\n                if (it == mp.end()) res.push_back(lin2(x, y0));\n                else res.push_back(lin2(x, it->second));\n            }\n        } else {\n            int x0 = anchorVal;\n            vector<int> otherX;\n            for (int x : X) if (x != x0) otherX.push_back(x);\n            if (rev) reverse(otherX.begin(), otherX.end());\n\n            int b = (int)Y.size();\n            int k = (int)otherX.size();\n            unordered_map<int,int> mp;\n            for (int i = 0; i < k; ++i) {\n                int y = Y[(offset + i) % b];\n                mp[y] = otherX[i];\n            }\n            for (int y : Y) {\n                auto it = mp.find(y);\n                if (it == mp.end()) res.push_back(lin2(x0, y));\n                else res.push_back(lin2(it->second, y));\n            }\n        }\n\n        sort(res.begin(), res.end());\n        res.erase(unique(res.begin(), res.end()), res.end());\n        return res;\n    }\n\n    vector<vector<LayerState>> make_star_states(const ObjData& o) const {\n        vector<vector<LayerState>> states(D);\n        for (int z = 0; z < D; ++z) {\n            set<vector<int>> seen;\n            int a = (int)o.Xs[z].size();\n            int b = (int)o.Ys[z].size();\n\n            if (a >= b) {\n                for (int y0 : o.Ys[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, a); ++off) {\n                            auto cells = build_star_layer_cells(o, z, true, y0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            } else {\n                for (int x0 : o.Xs[z]) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        for (int off = 0; off < max(1, b); ++off) {\n                            auto cells = build_star_layer_cells(o, z, false, x0, rev, off);\n                            if (seen.insert(cells).second) states[z].push_back({cells});\n                        }\n                    }\n                }\n            }\n        }\n        return states;\n    }\n\n    int overlap2d(const vector<int>& a, const vector<int>& b) const {\n        int i = 0, j = 0, cnt = 0;\n        while (i < (int)a.size() && j < (int)b.size()) {\n            if (a[i] == b[j]) {\n                ++cnt; ++i; ++j;\n            } else if (a[i] < b[j]) ++i;\n            else ++j;\n        }\n        return cnt;\n    }\n\n    vector<vector<int>> star_dp_scores(const vector<vector<LayerState>>& states, vector<vector<int>>& prv) const {\n        vector<vector<int>> dp(D);\n        prv.assign(D, {});\n        dp[0].assign(states[0].size(), 0);\n        prv[0].assign(states[0].size(), -1);\n\n        for (int z = 1; z < D; ++z) {\n            dp[z].assign(states[z].size(), -1000000000);\n            prv[z].assign(states[z].size(), -1);\n            for (int j = 0; j < (int)states[z].size(); ++j) {\n                for (int i = 0; i < (int)states[z-1].size(); ++i) {\n                    int sc = overlap2d(states[z-1][i].cells2, states[z][j].cells2);\n                    int cand = dp[z-1][i] + sc;\n                    if (cand > dp[z][j]) {\n                        dp[z][j] = cand;\n                        prv[z][j] = i;\n                    }\n                }\n            }\n        }\n        return dp;\n    }\n\n    OccCandidate reconstruct_star_occ(const vector<vector<LayerState>>& states, const vector<vector<int>>& prv, int lastIdx, const string& name) const {\n        vector<int> choice(D);\n        int cur = lastIdx;\n        for (int z = D - 1; z >= 0; --z) {\n            choice[z] = cur;\n            cur = prv[z][cur];\n            if (z == 0) break;\n        }\n\n        vector<char> occ(D * D * D, 0);\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : states[z][choice[z]].cells2) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n            }\n        }\n        int V = count(occ.begin(), occ.end(), 1);\n        return {move(occ), V, name};\n    }\n\n    vector<OccCandidate> build_star_candidates(const ObjData& o, const string& baseName, int topK = 5) const {\n        vector<OccCandidate> res;\n        auto states = make_star_states(o);\n        vector<vector<int>> prv;\n        auto dp = star_dp_scores(states, prv);\n\n        vector<int> ord(states[D-1].size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dp[D-1][a] > dp[D-1][b];\n        });\n\n        topK = min(topK, (int)ord.size());\n        for (int t = 0; t < topK; ++t) {\n            res.push_back(reconstruct_star_occ(states, prv, ord[t], baseName + \"_dp\" + to_string(t)));\n        }\n        return res;\n    }\n\n    vector<int> occ_to_layer_cells2(const vector<char>& occ, int z) const {\n        vector<int> cells;\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) {\n            if (occ[lin(x,y,z)]) cells.push_back(lin2(x,y));\n        }\n        return cells;\n    }\n\n    vector<int> solve_mincover_layer_weight(const ObjData& o, int z, const vector<int>& weight) const {\n        const auto& X = o.Xs[z];\n        const auto& Y = o.Ys[z];\n        int a = (int)X.size();\n        int b = (int)Y.size();\n\n        if (a >= b) {\n            vector<vector<int>> dp(a + 1, vector<int>(1 << b, -1000000000));\n            vector<vector<short>> prvMask(a + 1, vector<short>(1 << b, -1));\n            vector<vector<short>> prvTake(a + 1, vector<short>(1 << b, -1));\n            dp[0][0] = 0;\n\n            for (int i = 0; i < a; ++i) {\n                for (int mask = 0; mask < (1 << b); ++mask) {\n                    if (dp[i][mask] < -100000000) continue;\n                    for (int j = 0; j < b; ++j) {\n                        int cell = lin2(X[i], Y[j]);\n                        int nmask = mask | (1 << j);\n                        int cand = dp[i][mask] + weight[cell];\n                        if (cand > dp[i+1][nmask]) {\n                            dp[i+1][nmask] = cand;\n                            prvMask[i+1][nmask] = mask;\n                            prvTake[i+1][nmask] = j;\n                        }\n                    }\n                }\n            }\n\n            int mask = (1 << b) - 1;\n            vector<int> take(a);\n            for (int i = a; i >= 1; --i) {\n                take[i-1] = prvTake[i][mask];\n                mask = prvMask[i][mask];\n            }\n\n            vector<int> cells;\n            cells.reserve(a);\n            for (int i = 0; i < a; ++i) cells.push_back(lin2(X[i], Y[take[i]]));\n            sort(cells.begin(), cells.end());\n            return cells;\n        } else {\n            vector<vector<int>> dp(b + 1, vector<int>(1 << a, -1000000000));\n            vector<vector<short>> prvMask(b + 1, vector<short>(1 << a, -1));\n            vector<vector<short>> prvTake(b + 1, vector<short>(1 << a, -1));\n            dp[0][0] = 0;\n\n            for (int i = 0; i < b; ++i) {\n                for (int mask = 0; mask < (1 << a); ++mask) {\n                    if (dp[i][mask] < -100000000) continue;\n                    for (int j = 0; j < a; ++j) {\n                        int cell = lin2(X[j], Y[i]);\n                        int nmask = mask | (1 << j);\n                        int cand = dp[i][mask] + weight[cell];\n                        if (cand > dp[i+1][nmask]) {\n                            dp[i+1][nmask] = cand;\n                            prvMask[i+1][nmask] = mask;\n                            prvTake[i+1][nmask] = j;\n                        }\n                    }\n                }\n            }\n\n            int mask = (1 << a) - 1;\n            vector<int> take(b);\n            for (int i = b; i >= 1; --i) {\n                take[i-1] = prvTake[i][mask];\n                mask = prvMask[i][mask];\n            }\n\n            vector<int> cells;\n            cells.reserve(b);\n            for (int i = 0; i < b; ++i) cells.push_back(lin2(X[take[i]], Y[i]));\n            sort(cells.begin(), cells.end());\n            return cells;\n        }\n    }\n\n    vector<int> solve_mincover_layer(const ObjData& o, int z, const vector<int>* prevCells, const vector<int>* nextCells) const {\n        vector<int> weight(D * D, 0);\n        if (prevCells) for (int v : *prevCells) weight[v] += 100;\n        if (nextCells) for (int v : *nextCells) weight[v] += 100;\n        return solve_mincover_layer_weight(o, z, weight);\n    }\n\n    vector<int> random_mincover_layer(const ObjData& o, int z, mt19937& rng) const {\n        auto X = o.Xs[z];\n        auto Y = o.Ys[z];\n        shuffle(X.begin(), X.end(), rng);\n        shuffle(Y.begin(), Y.end(), rng);\n\n        vector<int> cells;\n        if ((int)X.size() >= (int)Y.size()) {\n            int a = (int)X.size(), b = (int)Y.size();\n            cells.reserve(a);\n            for (int i = 0; i < b; ++i) cells.push_back(lin2(X[i], Y[i]));\n            uniform_int_distribution<int> dist(0, b - 1);\n            for (int i = b; i < a; ++i) cells.push_back(lin2(X[i], Y[dist(rng)]));\n        } else {\n            int a = (int)X.size(), b = (int)Y.size();\n            cells.reserve(b);\n            for (int i = 0; i < a; ++i) cells.push_back(lin2(X[i], Y[i]));\n            uniform_int_distribution<int> dist(0, a - 1);\n            for (int i = a; i < b; ++i) cells.push_back(lin2(X[dist(rng)], Y[i]));\n        }\n        sort(cells.begin(), cells.end());\n        return cells;\n    }\n\n    vector<vector<int>> init_mincover_forward(const ObjData& o) const {\n        vector<vector<int>> layers(D);\n        layers[0] = solve_mincover_layer(o, 0, nullptr, nullptr);\n        for (int z = 1; z < D; ++z) {\n            layers[z] = solve_mincover_layer(o, z, &layers[z-1], nullptr);\n        }\n        return layers;\n    }\n\n    vector<vector<int>> init_mincover_backward(const ObjData& o) const {\n        vector<vector<int>> layers(D);\n        layers[D-1] = solve_mincover_layer(o, D-1, nullptr, nullptr);\n        for (int z = D - 2; z >= 0; --z) {\n            layers[z] = solve_mincover_layer(o, z, nullptr, &layers[z+1]);\n        }\n        return layers;\n    }\n\n    vector<vector<int>> init_from_occ_layers(const vector<char>& occ) const {\n        vector<vector<int>> layers(D);\n        for (int z = 0; z < D; ++z) layers[z] = occ_to_layer_cells2(occ, z);\n        return layers;\n    }\n\n    vector<vector<int>> random_init_mincover(const ObjData& o, mt19937& rng) const {\n        vector<vector<int>> layers(D);\n        for (int z = 0; z < D; ++z) layers[z] = random_mincover_layer(o, z, rng);\n        return layers;\n    }\n\n    vector<vector<int>> local_refine_mincover(const ObjData& o, vector<vector<int>> layers, int passes) const {\n        for (int pass = 0; pass < passes; ++pass) {\n            bool changed = false;\n            for (int z = 0; z < D; ++z) {\n                const vector<int>* prev = (z > 0 ? &layers[z-1] : nullptr);\n                const vector<int>* next = (z + 1 < D ? &layers[z+1] : nullptr);\n                auto best = solve_mincover_layer(o, z, prev, next);\n                if (best != layers[z]) {\n                    layers[z] = move(best);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n        return layers;\n    }\n\n    vector<vector<int>> local_refine_mincover_random(const ObjData& o, vector<vector<int>> layers, int passes, mt19937& rng) const {\n        vector<int> order(D);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; ++pass) {\n            shuffle(order.begin(), order.end(), rng);\n            for (int z : order) {\n                vector<int> weight(D * D, 0);\n                if (z > 0) for (int v : layers[z-1]) weight[v] += 100;\n                if (z + 1 < D) for (int v : layers[z+1]) weight[v] += 100;\n                if (z > 1) for (int v : layers[z-2]) weight[v] += 20;\n                if (z + 2 < D) for (int v : layers[z+2]) weight[v] += 20;\n                for (int v : layers[z]) weight[v] += 4;\n\n                for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                    weight[lin2(x, y)] += (int)(rng() % 3);\n                }\n                layers[z] = solve_mincover_layer_weight(o, z, weight);\n            }\n        }\n        return layers;\n    }\n\n    vector<vector<int>> global_refine_mincover(\n        const ObjData& o,\n        vector<vector<int>> layers,\n        int passes,\n        int w1,\n        int w2,\n        int wg,\n        int selfw,\n        mt19937* prng = nullptr\n    ) const {\n        vector<int> order(D);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; ++pass) {\n            vector<int> freq(D * D, 0);\n            for (int z = 0; z < D; ++z) for (int v : layers[z]) freq[v]++;\n\n            if (prng) shuffle(order.begin(), order.end(), *prng);\n\n            bool changed = false;\n            for (int z : order) {\n                for (int v : layers[z]) freq[v]--;\n\n                vector<int> weight(D * D, 0);\n                for (int v = 0; v < D * D; ++v) weight[v] += wg * freq[v];\n                if (z > 0) for (int v : layers[z-1]) weight[v] += w1;\n                if (z + 1 < D) for (int v : layers[z+1]) weight[v] += w1;\n                if (z > 1) for (int v : layers[z-2]) weight[v] += w2;\n                if (z + 2 < D) for (int v : layers[z+2]) weight[v] += w2;\n                for (int v : layers[z]) weight[v] += selfw;\n\n                if (prng) {\n                    for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                        weight[lin2(x, y)] += (int)((*prng)() & 1U);\n                    }\n                }\n\n                auto nxt = solve_mincover_layer_weight(o, z, weight);\n                if (nxt != layers[z]) changed = true;\n                layers[z] = move(nxt);\n                for (int v : layers[z]) freq[v]++;\n            }\n            if (!changed) break;\n        }\n\n        return layers;\n    }\n\n    vector<vector<int>> reference_refine_mincover(\n        const ObjData& o,\n        vector<vector<int>> layers,\n        const vector<vector<vector<int>>>& refs,\n        int passes,\n        int wsame,\n        int wnear,\n        int wglobal,\n        int w1,\n        int w2,\n        int selfw,\n        mt19937* prng = nullptr\n    ) const {\n        vector<int> refGlobal(D * D, 0);\n        vector<vector<int>> refSame(D, vector<int>(D * D, 0));\n        vector<vector<int>> refNear(D, vector<int>(D * D, 0));\n\n        for (auto &ref : refs) {\n            for (int z = 0; z < D; ++z) {\n                for (int v : ref[z]) {\n                    refGlobal[v]++;\n                    refSame[z][v]++;\n                    if (z > 0) refNear[z - 1][v]++;\n                    if (z + 1 < D) refNear[z + 1][v]++;\n                    if (z > 1) refNear[z - 2][v]++;\n                    if (z + 2 < D) refNear[z + 2][v]++;\n                }\n            }\n        }\n\n        vector<int> order(D);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; ++pass) {\n            vector<int> freq(D * D, 0);\n            for (int z = 0; z < D; ++z) for (int v : layers[z]) freq[v]++;\n\n            if (prng) shuffle(order.begin(), order.end(), *prng);\n\n            bool changed = false;\n            for (int z : order) {\n                for (int v : layers[z]) freq[v]--;\n\n                vector<int> weight(D * D, 0);\n                for (int v = 0; v < D * D; ++v) {\n                    weight[v] += wglobal * refGlobal[v];\n                    weight[v] += wsame * refSame[z][v];\n                    weight[v] += wnear * refNear[z][v];\n                    weight[v] += 5 * freq[v];\n                }\n                if (z > 0) for (int v : layers[z-1]) weight[v] += w1;\n                if (z + 1 < D) for (int v : layers[z+1]) weight[v] += w1;\n                if (z > 1) for (int v : layers[z-2]) weight[v] += w2;\n                if (z + 2 < D) for (int v : layers[z+2]) weight[v] += w2;\n                for (int v : layers[z]) weight[v] += selfw;\n\n                if (prng) {\n                    for (int x : o.Xs[z]) for (int y : o.Ys[z]) {\n                        weight[lin2(x, y)] += (int)((*prng)() & 1U);\n                    }\n                }\n\n                auto nxt = solve_mincover_layer_weight(o, z, weight);\n                if (nxt != layers[z]) changed = true;\n                layers[z] = move(nxt);\n                for (int v : layers[z]) freq[v]++;\n            }\n            if (!changed) break;\n        }\n\n        return layers;\n    }\n\n    OccCandidate layers_to_occ(const vector<vector<int>>& layers, const string& name) const {\n        vector<char> occ(D * D * D, 0);\n        int V = 0;\n        for (int z = 0; z < D; ++z) {\n            for (int v2 : layers[z]) {\n                int x = v2 / D;\n                int y = v2 % D;\n                occ[lin(x, y, z)] = 1;\n                ++V;\n            }\n        }\n        return {move(occ), V, name};\n    }\n\n    uint32_t hash_obj(const ObjData& o, uint32_t salt) const {\n        uint64_t h = salt;\n        auto upd = [&](char c) {\n            h ^= (uint64_t)(unsigned char)c + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        for (auto& s : o.f) for (char c : s) upd(c);\n        for (auto& s : o.r) for (char c : s) upd(c);\n        return (uint32_t)(h ^ (h >> 32));\n    }\n\n    vector<OccCandidate> build_mincover_candidates(const ObjData& o, const string& baseName, const vector<OccCandidate>& extraInits) const {\n        vector<OccCandidate> res;\n        mt19937 rng(hash_obj(o, 123456789u));\n\n        auto push_layers = [&](vector<vector<int>> layers, const string& name) {\n            res.push_back(layers_to_occ(layers, name));\n        };\n\n        vector<vector<vector<int>>> refPool;\n\n        auto process_seed = [&](vector<vector<int>> layers, const string& name) {\n            auto loc = local_refine_mincover(o, layers, 3);\n            push_layers(loc, name + \"_loc\");\n            refPool.push_back(loc);\n\n            auto glob = local_refine_mincover(o, layers, 2);\n            glob = global_refine_mincover(o, move(glob), 4, 90, 18, 7, 4, nullptr);\n            glob = local_refine_mincover(o, move(glob), 2);\n            push_layers(glob, name + \"_glob\");\n            refPool.push_back(glob);\n\n            auto glob2 = local_refine_mincover(o, layers, 1);\n            glob2 = global_refine_mincover(o, move(glob2), 4, 80, 24, 10, 3, nullptr);\n            glob2 = local_refine_mincover(o, move(glob2), 2);\n            push_layers(glob2, name + \"_glob2\");\n        };\n\n        process_seed(init_mincover_forward(o),  baseName + \"_fw\");\n        process_seed(init_mincover_backward(o), baseName + \"_bw\");\n        process_seed(init_from_occ_layers(build_min_occ(o, false)), baseName + \"_A\");\n        process_seed(init_from_occ_layers(build_min_occ(o, true)),  baseName + \"_B\");\n\n        for (int i = 0; i < (int)extraInits.size() && i < 4; ++i) {\n            auto layers = init_from_occ_layers(extraInits[i].occ);\n            layers = local_refine_mincover(o, move(layers), 2);\n            refPool.push_back(layers);\n\n            auto t = global_refine_mincover(o, move(layers), 4, 90, 18, 7, 4, nullptr);\n            t = local_refine_mincover(o, move(t), 2);\n            push_layers(t, baseName + \"_seed\" + to_string(i));\n        }\n\n        if (!refPool.empty()) {\n            auto c1 = refPool[0];\n            c1 = reference_refine_mincover(o, move(c1), refPool, 4, 38, 10, 4, 88, 20, 4, nullptr);\n            c1 = local_refine_mincover(o, move(c1), 2);\n            push_layers(c1, baseName + \"_cons0\");\n\n            auto c2 = refPool[min<int>(1, (int)refPool.size() - 1)];\n            c2 = reference_refine_mincover(o, move(c2), refPool, 4, 30, 12, 6, 84, 22, 3, nullptr);\n            c2 = local_refine_mincover(o, move(c2), 2);\n            push_layers(c2, baseName + \"_cons1\");\n\n            auto c3 = refPool[min<int>(2, (int)refPool.size() - 1)];\n            c3 = reference_refine_mincover(o, move(c3), refPool, 5, 26, 8, 8, 82, 24, 3, nullptr);\n            c3 = local_refine_mincover(o, move(c3), 2);\n            push_layers(c3, baseName + \"_cons2\");\n        }\n\n        for (int t = 0; t < 8; ++t) {\n            auto layers = random_init_mincover(o, rng);\n            layers = local_refine_mincover_random(o, move(layers), 4, rng);\n            layers = global_refine_mincover(o, move(layers), 4, 90, 18, 7, 4, &rng);\n            if (!refPool.empty() && (t & 1)) {\n                layers = reference_refine_mincover(o, move(layers), refPool, 3, 24, 8, 4, 80, 20, 3, &rng);\n            }\n            layers = local_refine_mincover(o, move(layers), 2);\n            push_layers(layers, baseName + \"_rnd\" + to_string(t));\n        }\n\n        return res;\n    }\n\n    vector<OccCandidate> build_occ_candidates(const ObjData& o) const {\n        vector<OccCandidate> cands;\n\n        auto add_occ = [&](OccCandidate c) {\n            for (auto& e : cands) {\n                if (e.occ == c.occ) return;\n            }\n            cands.push_back(move(c));\n        };\n\n        auto cross = build_cross_candidates(o, \"cross\", 4);\n        auto star = build_star_candidates(o, \"star\", 5);\n\n        for (auto& c : cross) add_occ(c);\n        for (auto& c : star) add_occ(c);\n\n        vector<OccCandidate> extraSeeds;\n        for (int i = 0; i < (int)star.size() && i < 3; ++i) extraSeeds.push_back(star[i]);\n        for (int i = 0; i < (int)cross.size() && i < 2; ++i) extraSeeds.push_back(cross[i]);\n\n        for (auto& c : build_mincover_candidates(o, \"mincov\", extraSeeds)) add_occ(move(c));\n\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, false);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minA\";\n            add_occ(move(c));\n        }\n        {\n            OccCandidate c;\n            c.occ = build_min_occ(o, true);\n            c.V = count(c.occ.begin(), c.occ.end(), 1);\n            c.name = \"minB\";\n            add_occ(move(c));\n        }\n\n        return cands;\n    }\n\n    bool cell_used_partition(const vector<char>& unused, int x, int y, int z) const {\n        if (x < 0 || x >= D || y < 0 || y >= D || z < 0 || z >= D) return false;\n        return unused[lin(x, y, z)];\n    }\n\n    void add_block_partition(Partition& p, const vector<int>& rawCells) {\n        vector<int> cells = rawCells;\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        int sig = canonical_id(cells);\n        int idx = (int)p.blocks.size();\n        p.blocks.push_back({(int)cells.size(), sig, cells});\n        p.bySig[sig].push_back(idx);\n    }\n\n    int boundary_score_partition(const vector<char>& unused, const vector<int>& cells) const {\n        static const int dx[6] = {1,-1,0,0,0,0};\n        static const int dy[6] = {0,0,1,-1,0,0};\n        static const int dz[6] = {0,0,0,0,1,-1};\n        auto inside = [&](int id) {\n            for (int v : cells) if (v == id) return true;\n            return false;\n        };\n        int score = 0;\n        for (int id : cells) {\n            auto [x,y,z] = invlin(id);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (unused[nid] && !inside(nid)) ++score;\n            }\n        }\n        return score;\n    }\n\n    bool find_best_segment_mask_partition(\n        const vector<char>& unused,\n        int L,\n        int allowedMask,\n        const array<int,3>& axisRank,\n        vector<int>& outCells\n    ) const {\n        const int dxs[3] = {1, 0, 0};\n        const int dys[3] = {0, 1, 0};\n        const int dzs[3] = {0, 0, 1};\n\n        bool found = false;\n        int bestExt = INT_MAX, bestRank = INT_MAX, bestPerp = INT_MAX, bestKey = INT_MAX;\n        vector<int> bestCells;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (!unused[lin(x, y, z)]) continue;\n\n            for (int dir = 0; dir < 3; ++dir) {\n                int bit = 1 << dir;\n                if (!(allowedMask & bit)) continue;\n\n                int dx = dxs[dir], dy = dys[dir], dz = dzs[dir];\n                int ex = x + (L - 1) * dx;\n                int ey = y + (L - 1) * dy;\n                int ez = z + (L - 1) * dz;\n                if (ex < 0 || ex >= D || ey < 0 || ey >= D || ez < 0 || ez >= D) continue;\n\n                vector<int> cells;\n                bool ok = true;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    int id = lin(nx, ny, nz);\n                    if (!unused[id]) { ok = false; break; }\n                    cells.push_back(id);\n                }\n                if (!ok) continue;\n\n                int ext = 0;\n                if (cell_used_partition(unused, x - dx, y - dy, z - dz)) ++ext;\n                if (cell_used_partition(unused, ex + dx, ey + dy, ez + dz)) ++ext;\n\n                int perp = 0;\n                for (int t = 0; t < L; ++t) {\n                    int nx = x + t * dx;\n                    int ny = y + t * dy;\n                    int nz = z + t * dz;\n                    if (dir != 0) {\n                        perp += cell_used_partition(unused, nx - 1, ny, nz);\n                        perp += cell_used_partition(unused, nx + 1, ny, nz);\n                    }\n                    if (dir != 1) {\n                        perp += cell_used_partition(unused, nx, ny - 1, nz);\n                        perp += cell_used_partition(unused, nx, ny + 1, nz);\n                    }\n                    if (dir != 2) {\n                        perp += cell_used_partition(unused, nx, ny, nz - 1);\n                        perp += cell_used_partition(unused, nx, ny, nz + 1);\n                    }\n                }\n\n                int rank = axisRank[dir];\n                int key = (((dir * D + x) * D + y) * D + z);\n\n                if (!found ||\n                    ext < bestExt ||\n                    (ext == bestExt && rank < bestRank) ||\n                    (ext == bestExt && rank == bestRank && perp < bestPerp) ||\n                    (ext == bestExt && rank == bestRank && perp == bestPerp && key < bestKey)) {\n                    found = true;\n                    bestExt = ext;\n                    bestRank = rank;\n                    bestPerp = perp;\n                    bestKey = key;\n                    bestCells = move(cells);\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(bestCells);\n        return true;\n    }\n\n    bool find_best_square4_partition(const vector<char>& unused, vector<int>& outCells) const {\n        bool found = false;\n        int bestBd = INT_MAX, bestKey = INT_MAX;\n        vector<int> best;\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            if (x + 1 < D && y + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x+1,y,z), lin(x,y+1,z), lin(x+1,y+1,z)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_partition(unused, c);\n                    int key = ((((0 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n            if (x + 1 < D && z + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x+1,y,z), lin(x,y,z+1), lin(x+1,y,z+1)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_partition(unused, c);\n                    int key = ((((1 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n            if (y + 1 < D && z + 1 < D) {\n                vector<int> c = {lin(x,y,z), lin(x,y+1,z), lin(x,y,z+1), lin(x,y+1,z+1)};\n                bool ok = true;\n                for (int id : c) if (!unused[id]) ok = false;\n                if (ok) {\n                    int bd = boundary_score_partition(unused, c);\n                    int key = ((((2 * D) + x) * D + y) * D + z);\n                    if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                        found = true; bestBd = bd; bestKey = key; best = c;\n                    }\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(best);\n        return true;\n    }\n\n    bool find_best_L3_partition(const vector<char>& unused, vector<int>& outCells) const {\n        bool found = false;\n        int bestBd = INT_MAX, bestKey = INT_MAX;\n        vector<int> best;\n\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n        const int ax[6] = {0,0,1,1,2,2};\n\n        for (int x = 0; x < D; ++x) for (int y = 0; y < D; ++y) for (int z = 0; z < D; ++z) {\n            int c0 = lin(x,y,z);\n            if (!unused[c0]) continue;\n            for (int d1 = 0; d1 < 6; ++d1) for (int d2 = d1 + 1; d2 < 6; ++d2) {\n                if (ax[d1] == ax[d2]) continue;\n                int x1 = x + dx[d1], y1 = y + dy[d1], z1 = z + dz[d1];\n                int x2 = x + dx[d2], y2 = y + dy[d2], z2 = z + dz[d2];\n                if (x1 < 0 || x1 >= D || y1 < 0 || y1 >= D || z1 < 0 || z1 >= D) continue;\n                if (x2 < 0 || x2 >= D || y2 < 0 || y2 >= D || z2 < 0 || z2 >= D) continue;\n                int c1 = lin(x1,y1,z1), c2 = lin(x2,y2,z2);\n                if (!unused[c1] || !unused[c2]) continue;\n                vector<int> c = {c0, c1, c2};\n                sort(c.begin(), c.end());\n                c.erase(unique(c.begin(), c.end()), c.end());\n                if ((int)c.size() != 3) continue;\n                int bd = boundary_score_partition(unused, c);\n                int key = (((((d1 * 6) + d2) * D + x) * D + y) * D + z);\n                if (!found || bd < bestBd || (bd == bestBd && key < bestKey)) {\n                    found = true; bestBd = bd; bestKey = key; best = c;\n                }\n            }\n        }\n\n        if (!found) return false;\n        outCells = move(best);\n        return true;\n    }\n\n    void extract_components_partition(vector<char>& unused, Partition& p) {\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        vector<char> vis(D * D * D, 0);\n        vector<int> q;\n\n        for (int s = 0; s < D * D * D; ++s) {\n            if (!unused[s] || vis[s]) continue;\n            q.clear();\n            q.push_back(s);\n            vis[s] = 1;\n            for (int qi = 0; qi < (int)q.size(); ++qi) {\n                int v = q[qi];\n                auto [x,y,z] = invlin(v);\n                for (int dir = 0; dir < 6; ++dir) {\n                    int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                    if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                    int nid = lin(nx, ny, nz);\n                    if (unused[nid] && !vis[nid]) {\n                        vis[nid] = 1;\n                        q.push_back(nid);\n                    }\n                }\n            }\n            for (int v : q) unused[v] = 0;\n            add_block_partition(p, q);\n        }\n    }\n\n    vector<pair<int,int>> maximum_domino_pairs_partition(const vector<char>& unused) const {\n        const int N = D * D * D;\n        vector<int> L_id(N, -1), R_id(N, -1);\n        vector<int> L_lin, R_lin;\n\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 = lin(x, y, z);\n            if (!unused[id]) continue;\n            if ((x + y + z) & 1) {\n                R_id[id] = (int)R_lin.size();\n                R_lin.push_back(id);\n            } else {\n                L_id[id] = (int)L_lin.size();\n                L_lin.push_back(id);\n            }\n        }\n\n        HopcroftKarp hk((int)L_lin.size(), (int)R_lin.size());\n        const int dx[6] = {1,-1,0,0,0,0};\n        const int dy[6] = {0,0,1,-1,0,0};\n        const int dz[6] = {0,0,0,0,1,-1};\n\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            auto [x,y,z] = invlin(L_lin[u]);\n            for (int dir = 0; dir < 6; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = lin(nx, ny, nz);\n                if (R_id[nid] != -1) hk.add_edge(u, R_id[nid]);\n            }\n        }\n\n        hk.max_matching();\n\n        vector<pair<int,int>> ret;\n        for (int u = 0; u < (int)L_lin.size(); ++u) {\n            if (hk.pairU[u] != -1) ret.push_back({L_lin[u], R_lin[hk.pairU[u]]});\n        }\n        return ret;\n    }\n\n    Partition build_partition_spec(const OccCandidate& occCand, const PartitionSpec& spec) {\n        Partition p;\n        p.V = occCand.V;\n        p.name = occCand.name + \":\" + spec.name;\n\n        vector<char> unused = occCand.occ;\n\n        for (int op : spec.ops) {\n            if (op == 1 || op == 2 || op == 4 || op == 7) {\n                int mask = op;\n                for (int L : spec.lens) {\n                    if (L < 3 || L > D) continue;\n                    while (true) {\n                        vector<int> seg;\n                        if (!find_best_segment_mask_partition(unused, L, mask, spec.axisRank, seg)) break;\n                        for (int id : seg) unused[id] = 0;\n                        add_block_partition(p, seg);\n                    }\n                }\n            } else if (op == 8) {\n                while (true) {\n                    vector<int> sq;\n                    if (!find_best_square4_partition(unused, sq)) break;\n                    for (int id : sq) unused[id] = 0;\n                    add_block_partition(p, sq);\n                }\n            } else if (op == 9) {\n                while (true) {\n                    vector<int> l3;\n                    if (!find_best_L3_partition(unused, l3)) break;\n                    for (int id : l3) unused[id] = 0;\n                    add_block_partition(p, l3);\n                }\n            } else if (op == 10) {\n                extract_components_partition(unused, p);\n            }\n        }\n\n        auto doms = maximum_domino_pairs_partition(unused);\n        vector<char> used2(D * D * D, 0);\n        for (auto [a, b] : doms) {\n            if (!unused[a] || !unused[b] || used2[a] || used2[b]) continue;\n            used2[a] = used2[b] = 1;\n            add_block_partition(p, vector<int>{a, b});\n        }\n        for (int i = 0; i < D * D * D; ++i) if (used2[i]) unused[i] = 0;\n\n        for (int i = 0; i < D * D * D; ++i) {\n            if (unused[i]) add_block_partition(p, vector<int>{i});\n        }\n\n        p.sigCounts.reserve(p.bySig.size());\n        for (auto &kv : p.bySig) p.sigCounts.push_back({kv.first, (int)kv.second.size()});\n        sort(p.sigCounts.begin(), p.sigCounts.end());\n        return p;\n    }\n\n    vector<PartitionSpec> make_partition_specs() const {\n        vector<PartitionSpec> specs;\n\n        vector<int> desc, asc, only3, only43, only4;\n        for (int L = D; L >= 3; --L) desc.push_back(L);\n        for (int L = 3; L <= D; ++L) asc.push_back(L);\n        if (D >= 3) only3 = {3};\n        if (D >= 4) only4 = {4};\n        if (D >= 4) only43.push_back(4);\n        if (D >= 3) only43.push_back(3);\n\n        auto add = [&](string name, vector<int> ops, const vector<int>& lens, array<int,3> rank) {\n            specs.push_back({name, ops, lens, rank});\n        };\n\n        add(\"all_zxy_desc\",   {7}, desc, {1,2,0});\n        add(\"all_xyz_desc\",   {7}, desc, {0,1,2});\n        add(\"all_zyx_asc\",    {7}, asc,  {1,2,0});\n        add(\"z_then_all\",     {4,7}, desc, {1,2,0});\n        add(\"x_then_all\",     {1,7}, desc, {0,2,1});\n        add(\"y_then_all\",     {2,7}, desc, {2,0,1});\n        add(\"z_only\",         {4}, desc, {1,2,0});\n        add(\"z_only_asc\",     {4}, asc,  {1,2,0});\n        add(\"z_then_all_asc\", {4,7}, asc, {1,2,0});\n        add(\"x_only\",         {1}, desc, {0,2,1});\n        add(\"y_only\",         {2}, desc, {2,0,1});\n        add(\"zxy_seq\",        {4,1,2,7}, desc, {1,2,0});\n        add(\"xyz_seq\",        {1,2,4,7}, desc, {0,1,2});\n\n        add(\"dom_only\",       {}, {}, {1,2,0});\n        if (!only3.empty()) {\n            add(\"all_only3\",   {7}, only3, {1,2,0});\n            add(\"z_only3\",     {4}, only3, {1,2,0});\n            add(\"z_then_all3\", {4,7}, only3, {1,2,0});\n        }\n        if (!only4.empty()) {\n            add(\"all_only4\",   {7}, only4, {1,2,0});\n            add(\"z_only4\",     {4}, only4, {1,2,0});\n        }\n        if (!only43.empty()) {\n            add(\"all_43\",      {7}, only43, {1,2,0});\n            add(\"z_43\",        {4}, only43, {1,2,0});\n            add(\"z_then_43\",   {4,7}, only43, {1,2,0});\n        }\n\n        add(\"all_sq_l3\",      {7,8,9}, desc, {1,2,0});\n        add(\"sq_l3_comp\",     {8,9,10}, desc, {1,2,0});\n        add(\"all_then_comp\",  {7,10}, desc, {1,2,0});\n        add(\"z_then_sq_comp\", {4,8,10}, desc, {1,2,0});\n        add(\"comp_only\",      {10}, desc, {1,2,0});\n\n        return specs;\n    }\n\n    string partition_signature(const Partition& p) const {\n        string s;\n        s.reserve(p.sigCounts.size() * 12);\n        for (auto [sig, cnt] : p.sigCounts) {\n            s += to_string(sig);\n            s += ':';\n            s += to_string(cnt);\n            s += ';';\n        }\n        return s;\n    }\n\n    vector<Partition> build_partitions(const vector<OccCandidate>& occs) {\n        auto specs = make_partition_specs();\n        vector<Partition> ret;\n        unordered_set<string> seen;\n\n        for (auto &occ : occs) {\n            for (auto &spec : specs) {\n                Partition p = build_partition_spec(occ, spec);\n                string key = partition_signature(p);\n                if (seen.insert(key).second) ret.push_back(move(p));\n            }\n        }\n        return ret;\n    }\n\n    long double eval_pair(const Partition& A, const Partition& B) const {\n        long double score = (long double)A.V + (long double)B.V;\n        int i = 0, j = 0;\n        while (i < (int)A.sigCounts.size() && j < (int)B.sigCounts.size()) {\n            if (A.sigCounts[i].first == B.sigCounts[j].first) {\n                int sig = A.sigCounts[i].first;\n                int k = min(A.sigCounts[i].second, B.sigCounts[j].second);\n                int s = sigSize[sig];\n                score -= (long double)2 * s * k;\n                score += (long double)k / (long double)s;\n                ++i; ++j;\n            } else if (A.sigCounts[i].first < B.sigCounts[j].first) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        return score;\n    }\n\n    pair<vector<int>, vector<int>> build_output_arrays(const Partition& A, const Partition& B) const {\n        vector<int> outA(D * D * D, 0), outB(D * D * D, 0);\n        vector<char> usedA(A.blocks.size(), 0), usedB(B.blocks.size(), 0);\n\n        vector<tuple<int,int,int>> common;\n        int i = 0, j = 0;\n        while (i < (int)A.sigCounts.size() && j < (int)B.sigCounts.size()) {\n            if (A.sigCounts[i].first == B.sigCounts[j].first) {\n                int sig = A.sigCounts[i].first;\n                int k = min(A.sigCounts[i].second, B.sigCounts[j].second);\n                if (k > 0) common.push_back({-sigSize[sig], sig, k});\n                ++i; ++j;\n            } else if (A.sigCounts[i].first < B.sigCounts[j].first) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        sort(common.begin(), common.end());\n\n        int id = 1;\n        for (auto [negSize, sig, k] : common) {\n            const auto& va = A.bySig.at(sig);\n            const auto& vb = B.bySig.at(sig);\n            for (int t = 0; t < k; ++t) {\n                int ia = va[t];\n                int ib = vb[t];\n                usedA[ia] = 1;\n                usedB[ib] = 1;\n                for (int c : A.blocks[ia].cells) outA[c] = id;\n                for (int c : B.blocks[ib].cells) outB[c] = id;\n                ++id;\n            }\n        }\n\n        for (int bi = 0; bi < (int)A.blocks.size(); ++bi) {\n            if (usedA[bi]) continue;\n            for (int c : A.blocks[bi].cells) outA[c] = id;\n            ++id;\n        }\n        for (int bi = 0; bi < (int)B.blocks.size(); ++bi) {\n            if (usedB[bi]) continue;\n            for (int c : B.blocks[bi].cells) outB[c] = id;\n            ++id;\n        }\n\n        return {outA, outB};\n    }\n\n    void solve() {\n        auto occ1 = build_occ_candidates(obj[0]);\n        auto occ2 = build_occ_candidates(obj[1]);\n\n        auto part1 = build_partitions(occ1);\n        auto part2 = build_partitions(occ2);\n\n        int bi = 0, bj = 0;\n        long double best = 1e100L;\n        for (int i = 0; i < (int)part1.size(); ++i) {\n            for (int j = 0; j < (int)part2.size(); ++j) {\n                long double sc = eval_pair(part1[i], part2[j]);\n                if (sc < best) {\n                    best = sc;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        auto [out1, out2] = build_output_arrays(part1[bi], part2[bj]);\n\n        int n = 0;\n        for (int v : out1) n = max(n, v);\n        for (int v : out2) n = max(n, v);\n\n        cout << n << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out1[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < D * D * D; ++i) {\n            if (i) cout << ' ';\n            cout << out2[i];\n        }\n        cout << '\\n';\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> f1(D), r1(D), f2(D), r2(D);\n    for (int i = 0; i < D; ++i) cin >> f1[i];\n    for (int i = 0; i < D; ++i) cin >> r1[i];\n    for (int i = 0; i < D; ++i) cin >> f2[i];\n    for (int i = 0; i < D; ++i) cin >> r2[i];\n\n    Solver solver(D);\n    solver.prepare_obj(0, f1, r1);\n    solver.prepare_obj(1, f2, r2);\n    solver.solve();\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }\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;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstruct Tree {\n    vector<char> edgeOn;\n    vector<char> vertexOn;\n};\n\nstruct Solution {\n    vector<int> P;\n    vector<char> B;\n    long long S = (1LL << 62);\n    bool feasible = false;\n};\n\nstatic const long long INF64 = (1LL << 60);\nstatic const int EXACT_TERMINAL_LIMIT = 12;\n\nint N, M, K;\nvector<int> X, Y;\nvector<Edge> edges;\nvector<int> A, Br;\nvector<vector<pair<int,int>>> g;\n\nvector<vector<long long>> distSP;\nvector<vector<int>> parentV, parentE;\nvector<vector<unsigned short>> reqPow;\nvector<vector<pair<int,int>>> coverList;\n\nchrono::steady_clock::time_point g_start;\ndouble TIME_LIMIT = 1.85;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nint ceil_sqrt_ll(long long x) {\n    long long r = 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\nlong long power_cost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nlong long tree_cost(const vector<char>& Eon) {\n    long long s = 0;\n    for (int e = 0; e < M; ++e) if (Eon[e]) s += edges[e].w;\n    return s;\n}\n\nlong long total_cost(const vector<int>& P, const vector<char>& Eon) {\n    return power_cost(P) + tree_cost(Eon);\n}\n\nvoid compute_all_pairs_shortest_paths() {\n    distSP.assign(N, vector<long long>(N, INF64));\n    parentV.assign(N, vector<int>(N, -1));\n    parentE.assign(N, vector<int>(N, -1));\n\n    for (int s = 0; s < N; ++s) {\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        distSP[s][s] = 0;\n        parentV[s][s] = s;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != distSP[s][v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < distSP[s][to]) {\n                    distSP[s][to] = nd;\n                    parentV[s][to] = v;\n                    parentE[s][to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n}\n\nvoid preprocess_cover_info() {\n    reqPow.assign(N, vector<unsigned short>(K, 5001));\n    coverList.assign(N, {});\n\n    for (int v = 0; v < N; ++v) {\n        coverList[v].reserve(K);\n        for (int k = 0; k < K; ++k) {\n            long long dx = 1LL * X[v] - A[k];\n            long long dy = 1LL * Y[v] - Br[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            if (p <= 5000) {\n                reqPow[v][k] = (unsigned short)p;\n                coverList[v].push_back({p, k});\n            }\n        }\n        sort(coverList[v].begin(), coverList[v].end());\n    }\n}\n\nbool verify_solution(const vector<int>& P, const vector<char>& Eon) {\n    vector<char> vis(N, 0);\n    queue<int> q;\n    vis[0] = 1;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (auto [to, eid] : g[v]) {\n            if (!Eon[eid]) continue;\n            if (!vis[to]) {\n                vis[to] = 1;\n                q.push(to);\n            }\n        }\n    }\n\n    for (int k = 0; k < K; ++k) {\n        bool ok = false;\n        for (int v = 0; v < N; ++v) {\n            if (!vis[v]) continue;\n            if (P[v] > 0 && reqPow[v][k] <= P[v]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nvoid add_path_from_source(int s, int t, vector<char>& inTree, vector<char>& edgeOn, vector<int>& newVertices) {\n    int cur = t;\n    while (cur != s) {\n        int pe = parentE[s][cur];\n        int pv = parentV[s][cur];\n        if (pe < 0 || pv < 0) break;\n        edgeOn[pe] = 1;\n        if (!inTree[cur]) {\n            inTree[cur] = 1;\n            newVertices.push_back(cur);\n        }\n        if (!inTree[pv]) {\n            inTree[pv] = 1;\n            newVertices.push_back(pv);\n        }\n        cur = pv;\n    }\n}\n\nvector<int> get_terminals_from_P(const vector<int>& P, vector<char>& isTerminal) {\n    isTerminal.assign(N, 0);\n    vector<int> terminals = {0};\n    isTerminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminals.push_back(i);\n            isTerminal[i] = 1;\n        }\n    }\n    return terminals;\n}\n\nTree finalize_tree_from_selected(const vector<char>& sel0, const vector<char>& isTerminal) {\n    vector<char> sel = sel0;\n    vector<vector<int>> inc(N);\n    vector<int> deg(N, 0);\n\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        int u = edges[e].u, v = edges[e].v;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n        deg[u]++;\n        deg[v]++;\n    }\n\n    queue<int> q;\n    for (int v = 0; v < N; ++v) if (!isTerminal[v] && deg[v] == 1) q.push(v);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (isTerminal[v] || deg[v] != 1) continue;\n        int remE = -1;\n        for (int e : inc[v]) if (sel[e]) { remE = e; break; }\n        if (remE == -1) continue;\n        sel[remE] = 0;\n        deg[v]--;\n        int to = edges[remE].u ^ edges[remE].v ^ v;\n        deg[to]--;\n        if (!isTerminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    Tree tr;\n    tr.edgeOn = sel;\n    tr.vertexOn.assign(N, 0);\n    tr.vertexOn[0] = 1;\n    for (int i = 0; i < N; ++i) if (isTerminal[i]) tr.vertexOn[i] = 1;\n    for (int e = 0; e < M; ++e) if (sel[e]) {\n        tr.vertexOn[edges[e].u] = 1;\n        tr.vertexOn[edges[e].v] = 1;\n    }\n    return tr;\n}\n\nTree build_tree_from_union_edges(const vector<char>& unionOn, const vector<char>& isTerminal) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int e = 0; e < M; ++e) if (unionOn[e]) ids.push_back(e);\n    sort(ids.begin(), ids.end(), [&](int a, int b) { return edges[a].w < edges[b].w; });\n\n    vector<char> sel(M, 0);\n    DSU dsu(N);\n    for (int e : ids) {\n        if (dsu.merge(edges[e].u, edges[e].v)) sel[e] = 1;\n    }\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nTree build_tree_metric(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    int T = (int)terminals.size();\n\n    if (T >= 2) {\n        vector<long long> best(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> used(T, 0);\n        best[0] = 0;\n\n        for (int it = 0; it < T; ++it) {\n            int v = -1;\n            for (int i = 0; i < T; ++i) if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                int s = terminals[par[v]];\n                int t = terminals[v];\n                int cur = t;\n                while (cur != s) {\n                    int pe = parentE[s][cur];\n                    int pv = parentV[s][cur];\n                    if (pe < 0 || pv < 0) break;\n                    unionOn[pe] = 1;\n                    cur = pv;\n                }\n            }\n\n            for (int to = 0; to < T; ++to) if (!used[to]) {\n                long long d = distSP[terminals[v]][terminals[to]];\n                if (d < best[to]) {\n                    best[to] = d;\n                    par[to] = v;\n                }\n            }\n        }\n    }\n\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_tree_sph(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> inTree(N, 0), unionOn(M, 0), doneTerminal(N, 0);\n    inTree[0] = 1;\n    doneTerminal[0] = 1;\n\n    int rem = 0;\n    for (int t : terminals) if (t != 0) rem++;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    while (rem > 0) {\n        int bestT = -1;\n        long long bestD = INF64;\n        for (int t : terminals) {\n            if (!doneTerminal[t] && bestDist[t] < bestD) {\n                bestD = bestDist[t];\n                bestT = t;\n            }\n        }\n        if (bestT == -1) break;\n\n        vector<int> newVertices;\n        add_path_from_source(bestFrom[bestT], bestT, inTree, unionOn, newVertices);\n        if (!inTree[bestT]) {\n            inTree[bestT] = 1;\n            newVertices.push_back(bestT);\n        }\n\n        for (int v : newVertices) {\n            if (isTerminal[v] && !doneTerminal[v]) {\n                doneTerminal[v] = 1;\n                rem--;\n            }\n        }\n        if (isTerminal[bestT] && !doneTerminal[bestT]) {\n            doneTerminal[bestT] = 1;\n            rem--;\n        }\n\n        for (int nv : newVertices) {\n            for (int t : terminals) {\n                if (!doneTerminal[t] && distSP[nv][t] < bestDist[t]) {\n                    bestDist[t] = distSP[nv][t];\n                    bestFrom[t] = nv;\n                }\n            }\n        }\n    }\n\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_tree_rootpaths(const vector<int>& terminals, const vector<char>& isTerminal) {\n    vector<char> unionOn(M, 0);\n    for (int t : terminals) if (t != 0) {\n        int cur = t;\n        while (cur != 0) {\n            int pe = parentE[0][cur];\n            int pv = parentV[0][cur];\n            if (pe < 0 || pv < 0) break;\n            unionOn[pe] = 1;\n            cur = pv;\n        }\n    }\n    return build_tree_from_union_edges(unionOn, isTerminal);\n}\n\nTree build_exact_tree(const vector<int>& terminals, const vector<char>& isTerminal) {\n    int T = (int)terminals.size();\n    int SZ = 1 << T;\n    auto IDX = [&](int mask, int v) { return mask * N + v; };\n\n    vector<long long> dp(SZ * N, INF64);\n    vector<int> kind(SZ * N, -3);\n    vector<short> prvV(SZ * N, -1), prvE(SZ * N, -1);\n\n    for (int i = 0; i < T; ++i) {\n        int id = IDX(1 << i, terminals[i]);\n        dp[id] = 0;\n        kind[id] = -1;\n    }\n\n    for (int mask = 1; mask < SZ; ++mask) {\n        if ((mask & (mask - 1)) != 0) {\n            for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n                int oth = mask ^ sub;\n                if (sub > oth) continue;\n                for (int v = 0; v < N; ++v) {\n                    long long a = dp[IDX(sub, v)];\n                    long long b = dp[IDX(oth, v)];\n                    if (a == INF64 || b == INF64) continue;\n                    long long nv = a + b;\n                    int id = IDX(mask, v);\n                    if (nv < dp[id]) {\n                        dp[id] = nv;\n                        kind[id] = sub;\n                        prvV[id] = -1;\n                        prvE[id] = -1;\n                    }\n                }\n            }\n        }\n\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        for (int v = 0; v < N; ++v) if (dp[IDX(mask, v)] < INF64) pq.push({dp[IDX(mask, v)], v});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dp[IDX(mask, v)]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + edges[eid].w;\n                int id = IDX(mask, to);\n                if (nd < dp[id]) {\n                    dp[id] = nd;\n                    kind[id] = -2;\n                    prvV[id] = (short)v;\n                    prvE[id] = (short)eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    }\n\n    int full = SZ - 1;\n    int bestV = 0;\n    for (int v = 1; v < N; ++v) if (dp[IDX(full, v)] < dp[IDX(full, bestV)]) bestV = v;\n\n    vector<char> sel(M, 0);\n    function<void(int,int)> rec = [&](int mask, int v) {\n        int id = IDX(mask, v);\n        int k = kind[id];\n        if (k == -3 || k == -1) return;\n        if (k == -2) {\n            int e = prvE[id], pv = prvV[id];\n            if (e >= 0) sel[e] = 1;\n            if (pv >= 0) rec(mask, pv);\n        } else {\n            rec(k, v);\n            rec(mask ^ k, v);\n        }\n    };\n    rec(full, bestV);\n\n    return finalize_tree_from_selected(sel, isTerminal);\n}\n\nvector<Tree> build_tree_candidates(const vector<int>& P, bool includeExact) {\n    vector<char> isTerminal;\n    vector<int> terminals = get_terminals_from_P(P, isTerminal);\n\n    vector<Tree> res;\n    res.push_back(build_tree_metric(terminals, isTerminal));\n    res.push_back(build_tree_sph(terminals, isTerminal));\n    res.push_back(build_tree_rootpaths(terminals, isTerminal));\n\n    if (includeExact && (int)terminals.size() <= EXACT_TERMINAL_LIMIT && elapsed_sec() < 1.68) {\n        res.push_back(build_exact_tree(terminals, isTerminal));\n    }\n    return res;\n}\n\nTree build_tree_by_P(const vector<int>& P, bool useExact) {\n    auto cands = build_tree_candidates(P, useExact);\n    int best = 0;\n    long long bestCost = tree_cost(cands[0].edgeOn);\n    for (int i = 1; i < (int)cands.size(); ++i) {\n        long long c = tree_cost(cands[i].edgeOn);\n        if (c < bestCost) {\n            bestCost = c;\n            best = i;\n        }\n    }\n    return cands[best];\n}\n\nvector<int> vertices_from_tree(const Tree& tr) {\n    vector<int> vs;\n    for (int i = 0; i < N; ++i) if (tr.vertexOn[i]) vs.push_back(i);\n    return vs;\n}\n\nvoid shrink_exclusive(vector<int>& P, const vector<int>& allowed) {\n    while (true) {\n        vector<int> cnt(K, 0);\n        for (int v : allowed) if (P[v] > 0) {\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) if (reqPow[v][k] <= pv) cnt[k]++;\n        }\n\n        bool changed = false;\n        for (int v : allowed) if (P[v] > 0) {\n            int oldP = P[v], need = 0;\n            for (int k = 0; k < K; ++k) {\n                if (reqPow[v][k] <= oldP && cnt[k] == 1) need = max(need, (int)reqPow[v][k]);\n            }\n            if (need < oldP) {\n                for (int k = 0; k < K; ++k) {\n                    if (reqPow[v][k] <= oldP && reqPow[v][k] > need) cnt[k]--;\n                }\n                P[v] = need;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\nvector<int> greedy_cover_fixed_set(const vector<int>& allowed, vector<int> P) {\n    vector<char> ok(N, 0);\n    for (int v : allowed) ok[v] = 1;\n    for (int i = 0; i < N; ++i) if (!ok[i]) P[i] = 0;\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    for (int v : allowed) if (P[v] > 0) {\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : allowed) {\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n                if (rp > P[v] && gain > 0) {\n                    long double extra = (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) {\n            for (int k = 0; k < K && bestV == -1; ++k) if (!covered[k]) {\n                for (int v : allowed) {\n                    int rp = reqPow[v][k];\n                    if (rp <= 5000 && rp > P[v]) {\n                        bestV = v;\n                        bestP = rp;\n                        break;\n                    }\n                }\n            }\n            if (bestV == -1) break;\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    shrink_exclusive(P, allowed);\n    return P;\n}\n\nvector<int> greedy_cover_with_conn(const vector<int>& candidates, vector<int> P, vector<char> inConn, double connFactor) {\n    for (int i = 0; i < N; ++i) if (P[i] > 0) inConn[i] = 1;\n    inConn[0] = 1;\n\n    vector<long long> bestDist(N, INF64);\n    for (int i = 0; i < N; ++i) if (inConn[i]) {\n        for (int j = 0; j < N; ++j) bestDist[j] = min(bestDist[j], distSP[i][j]);\n    }\n\n    vector<char> covered(K, 0);\n    int rem = K;\n    for (int v = 0; v < N; ++v) if (P[v] > 0) {\n        int pv = P[v];\n        for (auto [rp, k] : coverList[v]) {\n            if (rp > pv) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n    }\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v : candidates) {\n            long double conn = inConn[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0;\n            int sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) break;\n\n        if (!inConn[bestV]) {\n            inConn[bestV] = 1;\n            for (int t = 0; t < N; ++t) bestDist[t] = min(bestDist[t], distSP[bestV][t]);\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    vector<int> allv = candidates;\n    sort(allv.begin(), allv.end());\n    allv.erase(unique(allv.begin(), allv.end()), allv.end());\n    shrink_exclusive(P, allv);\n    return P;\n}\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> treeVertex;\n};\n\nInitialState initial_connected_greedy(double connFactor) {\n    vector<int> P(N, 0);\n    vector<char> inTree(N, 0), edgeOn(M, 0);\n    inTree[0] = 1;\n\n    vector<long long> bestDist = distSP[0];\n    vector<int> bestFrom(N, 0);\n\n    vector<char> covered(K, 0);\n    int rem = K;\n\n    while (rem > 0) {\n        int bestV = -1, bestP = -1, bestGain = -1;\n        long double bestMetric = 1e100L, bestExtra = 1e100L;\n\n        for (int v = 0; v < N; ++v) {\n            long double conn = inTree[v] ? 0.0L : (long double)connFactor * (long double)bestDist[v];\n            int gain = 0, sz = (int)coverList[v].size();\n\n            for (int i = 0; i < sz; ) {\n                int rp = coverList[v][i].first;\n                int j = i;\n                while (j < sz && coverList[v][j].first == rp) {\n                    if (!covered[coverList[v][j].second]) gain++;\n                    j++;\n                }\n                if (rp > P[v] && gain > 0) {\n                    long double extra = conn + (long double)rp * rp - (long double)P[v] * P[v];\n                    long double metric = extra / gain;\n                    if (metric < bestMetric - 1e-18L ||\n                        (fabsl(metric - bestMetric) <= 1e-18L &&\n                         (extra < bestExtra - 1e-18L ||\n                          (fabsl(extra - bestExtra) <= 1e-18L && gain > bestGain)))) {\n                        bestMetric = metric;\n                        bestExtra = extra;\n                        bestV = v;\n                        bestP = rp;\n                        bestGain = gain;\n                    }\n                }\n                i = j;\n            }\n        }\n\n        if (bestV == -1) break;\n\n        if (!inTree[bestV]) {\n            vector<int> newVertices;\n            add_path_from_source(bestFrom[bestV], bestV, inTree, edgeOn, newVertices);\n            if (!inTree[bestV]) {\n                inTree[bestV] = 1;\n                newVertices.push_back(bestV);\n            }\n            for (int nv : newVertices) {\n                for (int t = 0; t < N; ++t) {\n                    if (distSP[nv][t] < bestDist[t]) {\n                        bestDist[t] = distSP[nv][t];\n                        bestFrom[t] = nv;\n                    }\n                }\n            }\n        }\n\n        P[bestV] = bestP;\n        for (auto [rp, k] : coverList[bestV]) {\n            if (rp > bestP) break;\n            if (!covered[k]) {\n                covered[k] = 1;\n                rem--;\n            }\n        }\n\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    return {P, inTree};\n}\n\npair<vector<int>, Tree> normalize_solution(vector<int> P, bool useExact, int rounds, bool richFinal) {\n    Tree tr;\n    for (int it = 0; it < rounds; ++it) {\n        tr = build_tree_by_P(P, false);\n        vector<int> allowed = vertices_from_tree(tr);\n        P = greedy_cover_fixed_set(allowed, P);\n        if (elapsed_sec() > TIME_LIMIT) break;\n    }\n\n    if (richFinal && elapsed_sec() < 1.70) {\n        auto cands = build_tree_candidates(P, useExact);\n\n        struct CandEval {\n            long long val;\n            int idx;\n            vector<int> P2;\n        };\n        vector<CandEval> evals;\n        evals.reserve(cands.size());\n\n        int evalCnt = (elapsed_sec() < 1.25 ? (int)cands.size() : min<int>((int)cands.size(), 3));\n        vector<pair<long long,int>> ord;\n        for (int i = 0; i < (int)cands.size(); ++i) ord.push_back({tree_cost(cands[i].edgeOn), i});\n        sort(ord.begin(), ord.end());\n\n        for (int z = 0; z < evalCnt; ++z) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int idx = ord[z].second;\n            vector<int> allowed = vertices_from_tree(cands[idx]);\n            vector<int> P2 = greedy_cover_fixed_set(allowed, P);\n            evals.push_back({power_cost(P2) + tree_cost(cands[idx].edgeOn), idx, move(P2)});\n        }\n\n        if (!evals.empty()) {\n            sort(evals.begin(), evals.end(), [&](const CandEval& a, const CandEval& b) {\n                return a.val < b.val;\n            });\n            P = evals[0].P2;\n            tr = cands[evals[0].idx];\n        }\n    }\n\n    tr = build_tree_by_P(P, useExact);\n    {\n        vector<int> allowed = vertices_from_tree(tr);\n        P = greedy_cover_fixed_set(allowed, P);\n    }\n    tr = build_tree_by_P(P, useExact);\n    return {P, tr};\n}\n\n// normalize_solution() returns feasible states, so inner verify() calls are omitted.\n\nvector<int> local_improve_fixed_tree_full(vector<int> P, int candLimit, int rounds) {\n    for (int round = 0; round < rounds; ++round) {\n        if (elapsed_sec() > 1.64) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1, false);\n        P.swap(Pnorm);\n        long long curCost = total_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> allowed = vertices_from_tree(tr);\n        vector<int> cand;\n        for (int i = 0; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            return sa > sb;\n        });\n\n        int lim = min<int>((int)cand.size(), candLimit);\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n        bool improved = false;\n\n        for (int i = 0; i < lim; ++i) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int v = cand[i];\n            vector<int> P2 = P;\n            P2[v] = 0;\n            P2 = greedy_cover_fixed_set(allowed, P2);\n            auto [P3, tr3] = normalize_solution(P2, false, 1, false);\n            long long c3 = total_cost(P3, tr3.edgeOn);\n            if (c3 < bestCost) {\n                bestCost = c3;\n                bestP = P3;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n    return P;\n}\n\nvector<int> local_improve_replace_in_tree(vector<int> P, int vLimit, int uTry, int rounds) {\n    for (int round = 0; round < rounds; ++round) {\n        if (elapsed_sec() > 1.70) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1, false);\n        P.swap(Pnorm);\n        long long curCost = total_cost(P, tr.edgeOn);\n\n        vector<int> allowed = vertices_from_tree(tr);\n\n        vector<int> cnt(K, 0);\n        for (int v = 0; v < N; ++v) if (P[v] > 0) {\n            int pv = P[v];\n            for (int k = 0; k < K; ++k) if (reqPow[v][k] <= pv) cnt[k]++;\n        }\n\n        vector<int> active;\n        for (int i = 0; i < N; ++i) if (P[i] > 0) active.push_back(i);\n        sort(active.begin(), active.end(), [&](int a, int b) {\n            return 1LL * P[a] * P[a] > 1LL * P[b] * P[b];\n        });\n\n        int limV = min<int>((int)active.size(), vLimit);\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n        bool improved = false;\n\n        for (int ii = 0; ii < limV; ++ii) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int v = active[ii];\n\n            vector<int> uniq;\n            uniq.reserve(K);\n            for (int k = 0; k < K; ++k) {\n                if (cnt[k] == 1 && reqPow[v][k] <= P[v]) uniq.push_back(k);\n            }\n            if (uniq.empty()) continue;\n\n            vector<tuple<long long,int,int>> candU;\n            candU.reserve(allowed.size());\n\n            for (int u : allowed) {\n                if (u == v) continue;\n                int rp = P[u];\n                bool ok = true;\n                for (int k : uniq) {\n                    int rq = reqPow[u][k];\n                    if (rq > 5000) {\n                        ok = false;\n                        break;\n                    }\n                    rp = max(rp, rq);\n                }\n                if (!ok) continue;\n                long long extra = 1LL * rp * rp - 1LL * P[u] * P[u] - 1LL * P[v] * P[v];\n                candU.emplace_back(extra, u, rp);\n            }\n\n            sort(candU.begin(), candU.end());\n            int limU = min<int>((int)candU.size(), uTry);\n\n            for (int z = 0; z < limU; ++z) {\n                if (elapsed_sec() > TIME_LIMIT) break;\n                auto [dummy, u, rp] = candU[z];\n                (void)dummy;\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2[u] = max(P2[u], rp);\n                P2 = greedy_cover_fixed_set(allowed, P2);\n                auto [P3, tr3] = normalize_solution(P2, false, 1, false);\n                long long c3 = total_cost(P3, tr3.edgeOn);\n                if (c3 < bestCost) {\n                    bestCost = c3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n\n    return P;\n}\n\nvector<int> local_improve_drop_search(vector<int> P, double repairFactor, int candLimit, int rounds) {\n    vector<int> allVertices(N);\n    iota(allVertices.begin(), allVertices.end(), 0);\n\n    for (int round = 0; round < rounds; ++round) {\n        if (elapsed_sec() > 1.72) break;\n\n        auto [Pnorm, tr] = normalize_solution(P, false, 1, false);\n        P.swap(Pnorm);\n        long long curCost = total_cost(P, tr.edgeOn);\n\n        vector<int> deg(N, 0);\n        vector<long long> leafW(N, 0);\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        for (int e = 0; e < M; ++e) if (tr.edgeOn[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (deg[u] == 1) leafW[u] = edges[e].w;\n            if (deg[v] == 1) leafW[v] = edges[e].w;\n        }\n\n        vector<int> cand;\n        for (int i = 0; i < N; ++i) if (P[i] > 0) cand.push_back(i);\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            long long sa = 1LL * P[a] * P[a] + (deg[a] == 1 ? leafW[a] : 0);\n            long long sb = 1LL * P[b] * P[b] + (deg[b] == 1 ? leafW[b] : 0);\n            if ((deg[a] == 1) != (deg[b] == 1)) return deg[a] == 1;\n            return sa > sb;\n        });\n\n        int lim = min<int>((int)cand.size(), candLimit);\n        vector<int> bestP = P;\n        long long bestCost = curCost;\n        bool improved = false;\n        vector<int> treeAllowed = vertices_from_tree(tr);\n\n        for (int idx = 0; idx < lim; ++idx) {\n            if (elapsed_sec() > TIME_LIMIT) break;\n            int v = cand[idx];\n\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_fixed_set(treeAllowed, P2);\n                auto [P3, tr3] = normalize_solution(P2, false, 1, false);\n                long long c3 = total_cost(P3, tr3.edgeOn);\n                if (c3 < bestCost) {\n                    bestCost = c3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n\n            if (elapsed_sec() > TIME_LIMIT) break;\n\n            {\n                vector<int> P2 = P;\n                P2[v] = 0;\n                P2 = greedy_cover_with_conn(allVertices, P2, tr.vertexOn, repairFactor);\n                auto [P3, tr3] = normalize_solution(P2, false, 1, false);\n                long long c3 = total_cost(P3, tr3.edgeOn);\n                if (c3 < bestCost) {\n                    bestCost = c3;\n                    bestP = P3;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n        P.swap(bestP);\n    }\n\n    return P;\n}\n\nSolution solve_attempt(double connFactor) {\n    Solution sol;\n\n    InitialState init = initial_connected_greedy(connFactor);\n    vector<int> allowed;\n    for (int i = 0; i < N; ++i) if (init.treeVertex[i]) allowed.push_back(i);\n\n    vector<int> P0(N, 0);\n    for (int v : allowed) P0[v] = init.P[v];\n    vector<int> P = greedy_cover_fixed_set(allowed, P0);\n\n    auto [P1, tr1] = normalize_solution(P, false, elapsed_sec() < 0.95 ? 2 : 1, false);\n    P.swap(P1);\n\n    if (elapsed_sec() < 0.98) {\n        P = local_improve_replace_in_tree(P, 4, 2, 1);\n    }\n    if (elapsed_sec() < 1.10) {\n        P = local_improve_fixed_tree_full(P, elapsed_sec() < 0.80 ? 20 : 14, elapsed_sec() < 0.90 ? 2 : 1);\n    }\n    if (elapsed_sec() < 1.46) {\n        P = local_improve_drop_search(P, max(0.6, connFactor), elapsed_sec() < 1.00 ? 10 : 7, elapsed_sec() < 1.10 ? 2 : 1);\n    }\n\n    auto [Pf, trf] = normalize_solution(P, true, elapsed_sec() < 1.58 ? 2 : 1, false);\n    sol.P = Pf;\n    sol.B = trf.edgeOn;\n    sol.S = total_cost(sol.P, sol.B);\n    sol.feasible = true;\n    return sol;\n}\n\nSolution solve_radio_attempt() {\n    Solution sol;\n    vector<int> allv(N);\n    iota(allv.begin(), allv.end(), 0);\n\n    vector<int> P = greedy_cover_fixed_set(allv, vector<int>(N, 0));\n    auto [P1, tr1] = normalize_solution(P, false, 1, false);\n    P.swap(P1);\n\n    if (elapsed_sec() < 0.75) {\n        P = local_improve_fixed_tree_full(P, 6, 1);\n    }\n\n    auto [Pf, trf] = normalize_solution(P, true, 1, false);\n    sol.P = Pf;\n    sol.B = trf.edgeOn;\n    sol.S = total_cost(sol.P, sol.B);\n    sol.feasible = true;\n    return sol;\n}\n\nvector<vector<int>> generate_polish_seeds_from_trees(const vector<int>& baseP, bool includeExact, int maxSeeds) {\n    vector<vector<int>> seeds;\n    auto cands = build_tree_candidates(baseP, includeExact);\n\n    struct SeedEval {\n        long long val;\n        vector<int> P;\n    };\n    vector<SeedEval> evals;\n    evals.reserve(cands.size());\n\n    for (auto& tr : cands) {\n        if (elapsed_sec() > TIME_LIMIT) break;\n        vector<int> allowed = vertices_from_tree(tr);\n        vector<int> P2 = greedy_cover_fixed_set(allowed, baseP);\n        evals.push_back({total_cost(P2, tr.edgeOn), move(P2)});\n    }\n\n    sort(evals.begin(), evals.end(), [&](const SeedEval& a, const SeedEval& b) {\n        return a.val < b.val;\n    });\n\n    for (int i = 0; i < (int)evals.size() && i < maxSeeds; ++i) {\n        seeds.push_back(evals[i].P);\n    }\n    return seeds;\n}\n\nSolution polish_solution(const Solution& base) {\n    Solution best = base;\n\n    auto try_update = [&](const vector<int>& seed, double repairFactor,\n                          int fixedCand, int fixedRounds,\n                          int replV, int replU, int replRounds,\n                          int dropCand, int dropRounds) {\n        if (elapsed_sec() > TIME_LIMIT) return;\n        vector<int> P = seed;\n        if (elapsed_sec() < 1.56) {\n            P = local_improve_fixed_tree_full(P, fixedCand, fixedRounds);\n        }\n        if (elapsed_sec() < 1.67) {\n            P = local_improve_replace_in_tree(P, replV, replU, replRounds);\n        }\n        if (elapsed_sec() < 1.77) {\n            P = local_improve_drop_search(P, repairFactor, dropCand, dropRounds);\n        }\n        auto [Pf, tr] = normalize_solution(P, true, 2, true);\n        long long S = total_cost(Pf, tr.edgeOn);\n        if (S < best.S) {\n            best.P = Pf;\n            best.B = tr.edgeOn;\n            best.S = S;\n            best.feasible = true;\n        }\n    };\n\n    try_update(best.P, 1.0, 24, 2, 8, 2, 1, 12, 2);\n    if (elapsed_sec() < 1.77) try_update(best.P, 0.75, 18, 1, 6, 2, 1, 9, 1);\n    if (elapsed_sec() < 1.80) try_update(best.P, 1.35, 18, 1, 6, 2, 1, 9, 1);\n\n    if (elapsed_sec() < 1.60) {\n        int seedCnt = elapsed_sec() < 1.35 ? 4 : 3;\n        auto seeds = generate_polish_seeds_from_trees(best.P, true, seedCnt);\n        for (int i = 0; i < (int)seeds.size(); ++i) {\n            if (elapsed_sec() > 1.80) break;\n            try_update(seeds[i], 1.0, 12, 1, 5, 1, 1, 8, 1);\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M >> K;\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; ++i) cin >> X[i] >> Y[i];\n\n    edges.resize(M);\n    g.assign(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, v, w};\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    A.resize(K);\n    Br.resize(K);\n    for (int i = 0; i < K; ++i) cin >> A[i] >> Br[i];\n\n    compute_all_pairs_shortest_paths();\n    preprocess_cover_info();\n\n    Solution best;\n\n    vector<double> factors = {0.7, 1.0, 1.4, 0.4};\n    for (double f : factors) {\n        if (elapsed_sec() > 1.15) break;\n        Solution cur = solve_attempt(f);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n    if (elapsed_sec() < 0.94) {\n        Solution cur = solve_attempt(2.0);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n    if (elapsed_sec() < 0.74) {\n        Solution cur = solve_attempt(0.0);\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n    if (elapsed_sec() < 0.66) {\n        Solution cur = solve_radio_attempt();\n        if (cur.feasible && (!best.feasible || cur.S < best.S)) best = cur;\n    }\n\n    if (!best.feasible) {\n        best = solve_attempt(1.0);\n    }\n\n    if (best.feasible && elapsed_sec() < TIME_LIMIT) {\n        best = polish_solution(best);\n    }\n\n    if (!best.feasible) {\n        vector<int> allv(N);\n        iota(allv.begin(), allv.end(), 0);\n        vector<int> P = greedy_cover_fixed_set(allv, vector<int>(N, 0));\n        auto [Pf, tr] = normalize_solution(P, true, 1, false);\n        best.P = Pf;\n        best.B = tr.edgeOn;\n        best.S = total_cost(best.P, best.B);\n        best.feasible = verify_solution(best.P, best.B);\n    }\n\n    if (!verify_solution(best.P, best.B)) {\n        vector<int> allv(N);\n        iota(allv.begin(), allv.end(), 0);\n        vector<int> P = greedy_cover_fixed_set(allv, vector<int>(N, 0));\n        auto [Pf, tr] = normalize_solution(P, true, 1, false);\n        best.P = Pf;\n        best.B = tr.edgeOn;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (i) cout << ' ';\n        cout << best.P[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < M; ++i) {\n        if (i) cout << ' ';\n        cout << (int)best.B[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr double TL = 1.92;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Board {\n    uint16_t a[N][N];\n};\n\nstruct Plan {\n    vector<int> order;\n    int cost = 0;\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} timer_global;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline long long path_weight(int row, int val) {\n    return 1024LL * (N - row) + val;\n}\n\n// Move the minimum in descendant triangle T(tx,ty) to (tx,ty).\nstatic int apply_move(Board& b, int tx, int ty, vector<Op>* ops = nullptr) {\n    int bi = tx, bj = ty;\n    int best = b.a[tx][ty];\n\n    for (int i = tx; i < N; ++i) {\n        int L = ty;\n        int R = ty + (i - tx);\n        for (int j = L; j <= R; ++j) {\n            if ((int)b.a[i][j] < best) {\n                best = b.a[i][j];\n                bi = i;\n                bj = j;\n            }\n        }\n    }\n\n    if (bi == tx && bj == ty) return 0;\n\n    static long long memo[N][N];\n    static int seen[N][N];\n    static pair<short, short> parent_[N][N];\n    static int token = 1;\n    ++token;\n\n    auto dfs = [&](auto&& self, int i, int j) -> long long {\n        if (i == tx && j == ty) return 0;\n        if (seen[i][j] == token) return memo[i][j];\n        seen[i][j] = token;\n\n        long long best_score = LLONG_MIN / 4;\n        pair<short, short> best_parent = {-1, -1};\n\n        int d = i - tx;\n        int k = j - ty;\n\n        if (k > 0) {\n            int pi = i - 1, pj = j - 1;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n        if (k < d) {\n            int pi = i - 1, pj = j;\n            long long cand = path_weight(pi, b.a[pi][pj]) + self(self, pi, pj);\n            if (cand > best_score) {\n                best_score = cand;\n                best_parent = {(short)pi, (short)pj};\n            }\n        }\n\n        parent_[i][j] = best_parent;\n        memo[i][j] = best_score;\n        return best_score;\n    };\n\n    dfs(dfs, bi, bj);\n\n    int cnt = 0;\n    int i = bi, j = bj;\n    while (!(i == tx && j == ty)) {\n        auto [pi, pj] = parent_[i][j];\n        swap(b.a[i][j], b.a[pi][pj]);\n        if (ops) ops->push_back({i, j, pi, pj});\n        i = pi;\n        j = pj;\n        ++cnt;\n    }\n    return cnt;\n}\n\nstatic int simulate_order(const Board& start, int x, const vector<int>& order,\n                          Board* out_board = nullptr, vector<Op>* ops = nullptr) {\n    Board cur = start;\n    int total = 0;\n    for (int y : order) total += apply_move(cur, x, y, ops);\n    if (out_board) *out_board = cur;\n    return total;\n}\n\nstatic vector<int> make_lr_order(int m, bool rev) {\n    vector<int> ord;\n    ord.reserve(m);\n    if (!rev) for (int i = 0; i < m; ++i) ord.push_back(i);\n    else for (int i = m - 1; i >= 0; --i) ord.push_back(i);\n    return ord;\n}\n\nstatic vector<int> make_center_out_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int mid = (m - 1) / 2;\n    ord.push_back(mid);\n    for (int d = 1; (int)ord.size() < m; ++d) {\n        if (mid - d >= 0) ord.push_back(mid - d);\n        if (mid + d < m) ord.push_back(mid + d);\n    }\n    return ord;\n}\n\nstatic vector<int> make_outside_in_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    int l = 0, r = m - 1;\n    while (l <= r) {\n        ord.push_back(l++);\n        if (l <= r) ord.push_back(r--);\n    }\n    return ord;\n}\n\nstatic vector<int> make_even_odd_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    for (int i = 0; i < m; i += 2) ord.push_back(i);\n    for (int i = 1; i < m; i += 2) ord.push_back(i);\n    return ord;\n}\n\nstatic vector<int> make_odd_even_order(int m) {\n    vector<int> ord;\n    ord.reserve(m);\n    for (int i = 1; i < m; i += 2) ord.push_back(i);\n    for (int i = 0; i < m; i += 2) ord.push_back(i);\n    return ord;\n}\n\nstatic Plan greedy_row_plan(const Board& start, int x, bool one_step_lookahead, int tie_mode = 0) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        int best_y = -1;\n        int best_add = INT_MAX;\n        int best_next = INT_MAX;\n        int best_tie2 = INT_MAX;\n        Board best_board{};\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            int nextv = 0;\n            if (one_step_lookahead && step + 1 < m) {\n                nextv = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    nextv = min(nextv, c2);\n                }\n            }\n\n            int tie2 = 0;\n            if (tie_mode == 1) tie2 = abs(2 * y - x);\n            else if (tie_mode == 2) tie2 = -abs(2 * y - x);\n            else tie2 = y;\n\n            bool better = false;\n            if (add != best_add) better = (add < best_add);\n            else if (one_step_lookahead && nextv != best_next) better = (nextv < best_next);\n            else if (tie2 != best_tie2) better = (tie2 < best_tie2);\n            else if (best_y == -1 || y < best_y) better = true;\n\n            if (better) {\n                best_y = y;\n                best_add = add;\n                best_next = nextv;\n                best_tie2 = tie2;\n                best_board = tmp;\n            }\n        }\n\n        ord.push_back(best_y);\n        total += best_add;\n        mask |= (1u << best_y);\n        cur = best_board;\n    }\n\n    return {ord, total};\n}\n\nstatic Plan randomized_greedy_row_plan(const Board& start, int x, XorShift64& rng, int variant) {\n    int m = x + 1;\n    Board cur = start;\n    vector<int> ord;\n    ord.reserve(m);\n    uint32_t mask = 0;\n    int total = 0;\n\n    for (int step = 0; step < m; ++step) {\n        struct Cand {\n            int y, add, tie1, tie2;\n            Board b;\n        };\n        vector<Cand> cands;\n        cands.reserve(m - step);\n\n        for (int y = 0; y < m; ++y) {\n            if (mask & (1u << y)) continue;\n\n            Board tmp = cur;\n            int add = apply_move(tmp, x, y, nullptr);\n\n            int tie1 = 0;\n            if (step + 1 < m) {\n                tie1 = INT_MAX;\n                for (int z = 0; z < m; ++z) {\n                    if (z == y) continue;\n                    if (mask & (1u << z)) continue;\n                    Board tmp2 = tmp;\n                    int c2 = apply_move(tmp2, x, z, nullptr);\n                    tie1 = min(tie1, c2);\n                }\n            }\n\n            int tie2;\n            if (variant == 0) tie2 = y;\n            else if (variant == 1) tie2 = abs(2 * y - x);\n            else if (variant == 2) tie2 = -abs(2 * y - x);\n            else tie2 = rng.next_int(0, 1000000);\n\n            cands.push_back({y, add, tie1, tie2, tmp});\n        }\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            if (a.add != b.add) return a.add < b.add;\n            if (a.tie1 != b.tie1) return a.tie1 < b.tie1;\n            if (a.tie2 != b.tie2) return a.tie2 < b.tie2;\n            return a.y < b.y;\n        });\n\n        int rcl = min<int>(4, cands.size());\n        int pick = 0;\n        int v = rng.next_int(0, 99);\n        if (rcl == 2) {\n            pick = (v < 72 ? 0 : 1);\n        } else if (rcl == 3) {\n            if (v < 55) pick = 0;\n            else if (v < 85) pick = 1;\n            else pick = 2;\n        } else if (rcl == 4) {\n            if (v < 48) pick = 0;\n            else if (v < 76) pick = 1;\n            else if (v < 92) pick = 2;\n            else pick = 3;\n        }\n\n        ord.push_back(cands[pick].y);\n        total += cands[pick].add;\n        mask |= (1u << cands[pick].y);\n        cur = cands[pick].b;\n    }\n\n    return {ord, total};\n}\n\nstruct BeamNode {\n    Board b;\n    uint32_t mask;\n    int cost;\n    int parent;\n    int choice;\n};\n\nstatic int beam_width_for_row(int x) {\n    int m = x + 1;\n    if (m <= 6) return 320;\n    if (m <= 10) return 180;\n    if (m <= 14) return 96;\n    if (m <= 18) return 56;\n    if (m <= 22) return 36;\n    return 24;\n}\n\nstatic Plan beam_row_plan(const Board& start, int x) {\n    int m = x + 1;\n    if (m == 1) return {{0}, 0};\n\n    int W = beam_width_for_row(x);\n    vector<vector<BeamNode>> levels(m + 1);\n    levels[0].push_back(BeamNode{start, 0u, 0, -1, -1});\n\n    auto cmp = [](const BeamNode& A, const BeamNode& B) {\n        if (A.cost != B.cost) return A.cost < B.cost;\n        return A.mask < B.mask;\n    };\n\n    int done = 0;\n    for (int depth = 0; depth < m; ++depth) {\n        if (timer_global.elapsed() > TL - 0.45) break;\n\n        vector<BeamNode> cand;\n        cand.reserve(levels[depth].size() * (m - depth));\n\n        for (int idx = 0; idx < (int)levels[depth].size(); ++idx) {\n            const auto& cur = levels[depth][idx];\n            for (int y = 0; y < m; ++y) {\n                if (cur.mask & (1u << y)) continue;\n                BeamNode nxt;\n                nxt.b = cur.b;\n                int add = apply_move(nxt.b, x, y, nullptr);\n                nxt.mask = cur.mask | (1u << y);\n                nxt.cost = cur.cost + add;\n                nxt.parent = idx;\n                nxt.choice = y;\n                cand.push_back(std::move(nxt));\n            }\n        }\n\n        if ((int)cand.size() > W) {\n            nth_element(cand.begin(), cand.begin() + W, cand.end(), cmp);\n            cand.resize(W);\n        }\n        sort(cand.begin(), cand.end(), cmp);\n        levels[depth + 1] = std::move(cand);\n        done = depth + 1;\n    }\n\n    if (done == 0) return greedy_row_plan(start, x, false);\n\n    int best_idx = 0;\n    for (int i = 1; i < (int)levels[done].size(); ++i) {\n        if (levels[done][i].cost < levels[done][best_idx].cost) best_idx = i;\n    }\n\n    vector<int> ord(done);\n    int idx = best_idx;\n    for (int depth = done; depth >= 1; --depth) {\n        ord[depth - 1] = levels[depth][idx].choice;\n        idx = levels[depth][idx].parent;\n    }\n\n    if ((int)ord.size() < m) {\n        Board cur = start;\n        uint32_t mask = 0;\n        for (int y : ord) {\n            apply_move(cur, x, y, nullptr);\n            mask |= (1u << y);\n        }\n        while ((int)ord.size() < m) {\n            int best_y = -1;\n            int best_add = INT_MAX;\n            Board best_board{};\n            for (int y = 0; y < m; ++y) {\n                if (mask & (1u << y)) continue;\n                Board tmp = cur;\n                int add = apply_move(tmp, x, y, nullptr);\n                if (add < best_add) {\n                    best_add = add;\n                    best_y = y;\n                    best_board = tmp;\n                }\n            }\n            ord.push_back(best_y);\n            cur = best_board;\n            mask |= (1u << best_y);\n        }\n    }\n\n    int c = simulate_order(start, x, ord, nullptr, nullptr);\n    return {ord, c};\n}\n\nstatic Plan local_improve_plan(const Board& start, int x, Plan base, XorShift64& rng) {\n    int m = x + 1;\n    Plan cur = base;\n    cur.cost = simulate_order(start, x, cur.order, nullptr, nullptr);\n\n    if (m <= 12 && timer_global.elapsed() < TL - 0.35) {\n        bool improved = true;\n        while (improved && timer_global.elapsed() < TL - 0.28) {\n            improved = false;\n            Plan best = cur;\n\n            for (int i = 0; i < m; ++i) {\n                for (int j = i + 1; j < m; ++j) {\n                    vector<int> ord = cur.order;\n                    swap(ord[i], ord[j]);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            for (int i = 0; i < m; ++i) {\n                for (int p = 0; p < m; ++p) {\n                    if (i == p) continue;\n                    vector<int> ord = cur.order;\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                    int c = simulate_order(start, x, ord, nullptr, nullptr);\n                    if (c < best.cost) {\n                        best = {std::move(ord), c};\n                        improved = true;\n                    }\n                }\n            }\n\n            if (improved) cur = best;\n        }\n    } else {\n        int iters = (m <= 18 ? 140 : 90);\n        if (timer_global.elapsed() > TL - 0.25) iters /= 2;\n\n        Plan best = cur;\n        for (int t = 0; t < iters && timer_global.elapsed() < TL - 0.16; ++t) {\n            vector<int> ord = cur.order;\n            int tp = rng.next_int(0, 2);\n\n            if (tp == 0) {\n                int i = rng.next_int(0, m - 1);\n                int j = rng.next_int(0, m - 1);\n                if (i != j) swap(ord[i], ord[j]);\n            } else if (tp == 1) {\n                int i = rng.next_int(0, m - 1);\n                int p = rng.next_int(0, m - 1);\n                if (i != p) {\n                    int v = ord[i];\n                    ord.erase(ord.begin() + i);\n                    ord.insert(ord.begin() + p, v);\n                }\n            } else {\n                int l = rng.next_int(0, m - 1);\n                int r = rng.next_int(0, m - 1);\n                if (l > r) swap(l, r);\n                reverse(ord.begin() + l, ord.begin() + r + 1);\n            }\n\n            int c = simulate_order(start, x, ord, nullptr, nullptr);\n            if (c < cur.cost || (c == cur.cost && rng.next_int(0, 3) == 0)) {\n                cur = {ord, c};\n                if (c < best.cost) best = cur;\n            }\n        }\n        if (best.cost < cur.cost) cur = best;\n    }\n\n    return cur;\n}\n\nstatic void add_plan(vector<Plan>& out, const Board& b, int x, vector<int> ord) {\n    int c = simulate_order(b, x, ord, nullptr, nullptr);\n    out.push_back({std::move(ord), c});\n}\n\nstatic vector<Plan> dedup_sort(vector<Plan> cands) {\n    sort(cands.begin(), cands.end(), [](const Plan& a, const Plan& b) {\n        if (a.order != b.order) return a.order < b.order;\n        return a.cost < b.cost;\n    });\n    vector<Plan> uniq;\n    for (auto& p : cands) {\n        if (uniq.empty() || uniq.back().order != p.order) uniq.push_back(p);\n        else if (p.cost < uniq.back().cost) uniq.back() = p;\n    }\n    sort(uniq.begin(), uniq.end(), [](const Plan& a, const Plan& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.order < b.order;\n    });\n    return uniq;\n}\n\nstatic vector<Plan> build_main_candidates(const Board& b, int x, XorShift64& rng) {\n    int m = x + 1;\n    vector<Plan> cands;\n\n    cands.push_back(greedy_row_plan(b, x, false, 0));\n    cands.push_back(greedy_row_plan(b, x, true, 0));\n    cands.push_back(greedy_row_plan(b, x, false, 1));\n    cands.push_back(greedy_row_plan(b, x, false, 2));\n\n    add_plan(cands, b, x, make_lr_order(m, false));\n    add_plan(cands, b, x, make_lr_order(m, true));\n    add_plan(cands, b, x, make_center_out_order(m));\n    add_plan(cands, b, x, make_outside_in_order(m));\n    add_plan(cands, b, x, make_even_odd_order(m));\n    add_plan(cands, b, x, make_odd_even_order(m));\n\n    if (timer_global.elapsed() < TL - 0.55) {\n        cands.push_back(beam_row_plan(b, x));\n    }\n\n    int rand_cnt = 0;\n    double rem = TL - timer_global.elapsed();\n    if (rem > 0.90) rand_cnt = (x >= 18 ? 10 : 7);\n    else if (rem > 0.60) rand_cnt = (x >= 18 ? 7 : 5);\n    else if (rem > 0.35) rand_cnt = (x >= 18 ? 4 : 3);\n    else if (rem > 0.22) rand_cnt = 2;\n\n    for (int i = 0; i < rand_cnt; ++i) {\n        cands.push_back(randomized_greedy_row_plan(b, x, rng, i % 4));\n    }\n\n    return dedup_sort(std::move(cands));\n}\n\nstatic vector<Plan> build_proxy_candidates(const Board& b, int x) {\n    int m = x + 1;\n    vector<Plan> cands;\n    cands.push_back(greedy_row_plan(b, x, false, 0));\n    cands.push_back(greedy_row_plan(b, x, true, 0));\n    add_plan(cands, b, x, make_lr_order(m, false));\n    add_plan(cands, b, x, make_lr_order(m, true));\n    add_plan(cands, b, x, make_center_out_order(m));\n    add_plan(cands, b, x, make_outside_in_order(m));\n    add_plan(cands, b, x, make_even_odd_order(m));\n    return dedup_sort(std::move(cands));\n}\n\nstatic int cheap_row_proxy(const Board& b, int x) {\n    if (x > N - 2) return 0;\n    auto cands = build_proxy_candidates(b, x);\n    return cands.front().cost;\n}\n\nstatic int two_row_proxy(const Board& b, int x) {\n    if (x > N - 2) return 0;\n\n    auto cands = build_proxy_candidates(b, x);\n    int topk = min<int>(3, cands.size());\n\n    int ans = INT_MAX;\n    for (int i = 0; i < topk; ++i) {\n        Board after;\n        int c1 = simulate_order(b, x, cands[i].order, &after, nullptr);\n        int val = c1;\n        if (x + 1 <= N - 2 && timer_global.elapsed() < TL - 0.10) {\n            val += cheap_row_proxy(after, x + 1);\n        }\n        ans = min(ans, val);\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board board{};\n    uint64_t seed = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v;\n            cin >> v;\n            board.a[x][y] = (uint16_t)v;\n            seed ^= (uint64_t)(v + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    XorShift64 rng(seed);\n\n    vector<Op> answer;\n    answer.reserve(6000);\n\n    for (int x = 0; x < N - 1; ++x) {\n        auto candidates = build_main_candidates(board, x, rng);\n\n        vector<Plan> pool;\n        int improve_k = min<int>(4, candidates.size());\n        for (int i = 0; i < improve_k && timer_global.elapsed() < TL - 0.24; ++i) {\n            pool.push_back(local_improve_plan(board, x, candidates[i], rng));\n        }\n        for (int i = 0; i < min<int>(4, candidates.size()); ++i) pool.push_back(candidates[i]);\n\n        auto final_cands = dedup_sort(std::move(pool));\n\n        int use_k = min<int>(6, final_cands.size());\n        int best_idx = 0;\n        int best_eval = INT_MAX;\n        int best_row_cost = INT_MAX;\n\n        for (int i = 0; i < use_k; ++i) {\n            Board after;\n            int row_cost = simulate_order(board, x, final_cands[i].order, &after, nullptr);\n\n            int eval = row_cost;\n            if (x + 1 <= N - 2 && timer_global.elapsed() < TL - 0.06) {\n                eval += two_row_proxy(after, x + 1);\n            }\n\n            if (eval < best_eval || (eval == best_eval && row_cost < best_row_cost)) {\n                best_eval = eval;\n                best_row_cost = row_cost;\n                best_idx = i;\n            }\n        }\n\n        simulate_order(board, x, final_cands[best_idx].order, &board, &answer);\n    }\n\n    cout << answer.size() << '\\n';\n    for (const auto& op : answer) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXV = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int lim) { return (int)(next_u64() % (uint64_t)lim); }\n};\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick(int n = 0) { init(n); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sum_prefix(int idx) const {\n        int s = 0;\n        for (++idx; idx > 0; idx -= idx & -idx) s += bit[idx];\n        return s;\n    }\n};\n\nstruct Solver {\n    int D, N, M;\n    int mid, entrance;\n\n    vector<vector<int>> nbrs;\n    array<unsigned char, MAXV> obstacle{};\n    array<unsigned char, MAXV> occupied{};\n    array<int, MAXV> label_at{};\n    array<unsigned char, MAXV> used{};\n    vector<int> free_ids;\n    int current_empty_count;\n\n    vector<int> main_order;\n    vector<int> alt_order;\n    array<int, MAXV> main_rank{};\n    array<int, MAXV> alt_rank{};\n    array<double, MAXV> avg_rank{};\n\n    Solver(int D_, int N_) : D(D_), N(N_) {\n        mid = (D - 1) / 2;\n        entrance = id(0, mid);\n        nbrs.assign(D * D, {});\n        label_at.fill(-1);\n        build_neighbors();\n    }\n\n    inline int id(int i, int j) const { return i * D + j; }\n    inline int row(int v) const { return v / D; }\n    inline int col(int v) const { return v % D; }\n\n    void build_neighbors() {\n        for (int i = 0; i < D; ++i) for (int j = 0; j < D; ++j) {\n            int v = id(i, j);\n            if (i > 0) nbrs[v].push_back(id(i - 1, j));\n            if (i + 1 < D) nbrs[v].push_back(id(i + 1, j));\n            if (j > 0) nbrs[v].push_back(id(i, j - 1));\n            if (j + 1 < D) nbrs[v].push_back(id(i, j + 1));\n        }\n    }\n\n    void finalize_init() {\n        free_ids.clear();\n        for (int v = 0; v < D * D; ++v) {\n            if (v == entrance) continue;\n            if (obstacle[v]) continue;\n            free_ids.push_back(v);\n        }\n        M = (int)free_ids.size();\n        current_empty_count = M + 1;\n        build_global_orders();\n    }\n\n    struct Analysis {\n        vector<int> legal;\n        array<int, MAXV> dist{};\n        array<int, MAXV> deg{};\n        array<int, MAXV> block_depth{};\n    };\n\n    Analysis analyze_empty(const array<unsigned char, MAXV>& occ) const {\n        Analysis A;\n        A.dist.fill(-1);\n        A.deg.fill(0);\n        A.block_depth.fill(0);\n\n        array<unsigned char, MAXV> active{};\n        for (int v = 0; v < D * D; ++v) {\n            active[v] = (!obstacle[v] && !occ[v]) ? 1 : 0;\n        }\n\n        for (int v = 0; v < D * D; ++v) {\n            if (!active[v]) continue;\n            int d = 0;\n            for (int to : nbrs[v]) if (active[to]) ++d;\n            A.deg[v] = d;\n        }\n\n        {\n            int q[MAXV];\n            int qh = 0, qt = 0;\n            q[qt++] = entrance;\n            A.dist[entrance] = 0;\n            while (qh < qt) {\n                int v = q[qh++];\n                for (int to : nbrs[v]) {\n                    if (!active[to]) continue;\n                    if (A.dist[to] != -1) continue;\n                    A.dist[to] = A.dist[v] + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        array<int, MAXV> ord, low;\n        array<unsigned char, MAXV> art{};\n        ord.fill(-1);\n        low.fill(-1);\n\n        vector<pair<int,int>> estack;\n        vector<vector<int>> comps;\n        int timer = 0;\n\n        auto make_component = [&](int a, int b) {\n            vector<int> vs;\n            while (true) {\n                auto e = estack.back();\n                estack.pop_back();\n                vs.push_back(e.first);\n                vs.push_back(e.second);\n                if (e.first == a && e.second == b) break;\n            }\n            sort(vs.begin(), vs.end());\n            vs.erase(unique(vs.begin(), vs.end()), vs.end());\n            comps.push_back(move(vs));\n        };\n\n        auto dfs = [&](auto&& self, int v, int p) -> void {\n            ord[v] = low[v] = timer++;\n            int child = 0;\n            for (int to : nbrs[v]) {\n                if (!active[to]) continue;\n                if (ord[to] == -1) {\n                    ++child;\n                    estack.push_back({v, to});\n                    self(self, to, v);\n                    low[v] = min(low[v], low[to]);\n                    if (p != -1 && low[to] >= ord[v]) art[v] = 1;\n                    if (low[to] >= ord[v]) make_component(v, to);\n                } else if (to != p && ord[to] < ord[v]) {\n                    low[v] = min(low[v], ord[to]);\n                    estack.push_back({v, to});\n                }\n            }\n            if (p == -1 && child > 1) art[v] = 1;\n        };\n        dfs(dfs, entrance, -1);\n\n        if (!comps.empty()) {\n            vector<vector<int>> inc_comp(D * D);\n            for (int c = 0; c < (int)comps.size(); ++c) {\n                for (int v : comps[c]) inc_comp[v].push_back(c);\n            }\n\n            vector<int> art_list;\n            for (int v = 0; v < D * D; ++v) if (active[v] && art[v]) art_list.push_back(v);\n\n            int C = (int)comps.size();\n            int Acount = (int)art_list.size();\n            vector<vector<int>> bc(C + Acount);\n\n            for (int ai = 0; ai < Acount; ++ai) {\n                int v = art_list[ai];\n                int anode = C + ai;\n                for (int c : inc_comp[v]) {\n                    bc[anode].push_back(c);\n                    bc[c].push_back(anode);\n                }\n            }\n\n            int root_comp = -1;\n            for (int c = 0; c < C; ++c) {\n                for (int v : comps[c]) if (v == entrance) {\n                    root_comp = c;\n                    break;\n                }\n                if (root_comp != -1) break;\n            }\n\n            vector<int> bcdist(C + Acount, -1);\n            queue<int> q;\n            q.push(root_comp);\n            bcdist[root_comp] = 0;\n            while (!q.empty()) {\n                int x = q.front(); q.pop();\n                for (int y : bc[x]) if (bcdist[y] == -1) {\n                    bcdist[y] = bcdist[x] + 1;\n                    q.push(y);\n                }\n            }\n\n            vector<int> comp_depth(C, 0);\n            for (int c = 0; c < C; ++c) comp_depth[c] = bcdist[c] / 2;\n\n            for (int v = 0; v < D * D; ++v) if (active[v]) {\n                int bd = 0;\n                for (int c : inc_comp[v]) bd = max(bd, comp_depth[c]);\n                A.block_depth[v] = bd;\n            }\n        }\n\n        for (int v : free_ids) {\n            if (occ[v]) continue;\n            if (art[v]) continue;\n            A.legal.push_back(v);\n        }\n        return A;\n    }\n\n    // ---------- global order precomputation ----------\n\n    tuple<int,int,int,int,int,int> fill_key_style(const Analysis& A, int v, int style) const {\n        int leaf = 4 - A.deg[v];\n        int per = row(v) + abs(col(v) - mid);\n\n        if (style == 0) {\n            return make_tuple(A.block_depth[v], A.dist[v], leaf, per, -A.deg[v], -v);\n        } else if (style == 1) {\n            return make_tuple(A.dist[v], A.block_depth[v], per, leaf, -A.deg[v], -v);\n        } else if (style == 2) {\n            return make_tuple(leaf, A.block_depth[v], A.dist[v], per, -A.deg[v], -v);\n        } else {\n            return make_tuple(A.block_depth[v], leaf, per, A.dist[v], -A.deg[v], -v);\n        }\n    }\n\n    int pick_fill_cell(array<unsigned char, MAXV>& occ, int style) const {\n        Analysis A = analyze_empty(occ);\n        auto legal = A.legal;\n\n        sort(legal.begin(), legal.end(), [&](int a, int b) {\n            return fill_key_style(A, a, style) > fill_key_style(A, b, style);\n        });\n\n        int K = min(5, (int)legal.size());\n        int best = legal[0];\n        tuple<int,int,int,int,int,int,int,int> bestKey = {-1,-1,-1,-1,-1,-1,-1,-1};\n\n        for (int i = 0; i < K; ++i) {\n            int v = legal[i];\n            array<unsigned char, MAXV> occ2 = occ;\n            occ2[v] = 1;\n            Analysis B = analyze_empty(occ2);\n\n            int next_bd = -1, next_dist = -1, next_legal = (int)B.legal.size();\n            for (int w : B.legal) {\n                next_bd = max(next_bd, B.block_depth[w]);\n                next_dist = max(next_dist, B.dist[w]);\n            }\n\n            int leaf = 4 - A.deg[v];\n            int per = row(v) + abs(col(v) - mid);\n\n            tuple<int,int,int,int,int,int,int,int> key;\n            if (style == 0) {\n                key = make_tuple(A.block_depth[v], A.dist[v], next_bd, next_dist, leaf, next_legal, per, -v);\n            } else if (style == 1) {\n                key = make_tuple(A.dist[v], A.block_depth[v], next_dist, next_bd, per, leaf, next_legal, -v);\n            } else if (style == 2) {\n                key = make_tuple(leaf, A.block_depth[v], next_bd, A.dist[v], next_legal, per, next_dist, -v);\n            } else {\n                key = make_tuple(A.block_depth[v], leaf, next_bd, per, next_legal, A.dist[v], next_dist, -v);\n            }\n\n            if (i == 0 || key > bestKey) {\n                best = v;\n                bestKey = key;\n            }\n        }\n        return best;\n    }\n\n    vector<int> build_order_style(int style) const {\n        array<unsigned char, MAXV> occ{};\n        vector<int> fill_order;\n        fill_order.reserve(M);\n\n        for (int step = 0; step < M; ++step) {\n            int v = pick_fill_cell(occ, style);\n            fill_order.push_back(v);\n            occ[v] = 1;\n        }\n\n        vector<int> unload_order(M);\n        for (int i = 0; i < M; ++i) unload_order[i] = fill_order[M - 1 - i];\n        return unload_order;\n    }\n\n    void build_global_orders() {\n        vector<vector<int>> ords;\n        for (int s = 0; s < 4; ++s) ords.push_back(build_order_style(s));\n\n        vector<array<int, MAXV>> ranks(4);\n        for (int s = 0; s < 4; ++s) {\n            ranks[s].fill(-1);\n            for (int i = 0; i < M; ++i) ranks[s][ords[s][i]] = i;\n        }\n\n        for (int v = 0; v < D * D; ++v) avg_rank[v] = 1e18;\n        vector<int> cells = free_ids;\n        for (int v : cells) {\n            double s = 0;\n            for (int k = 0; k < 4; ++k) s += ranks[k][v];\n            avg_rank[v] = s / 4.0;\n        }\n\n        sort(cells.begin(), cells.end(), [&](int a, int b) {\n            if (fabs(avg_rank[a] - avg_rank[b]) > 1e-9) return avg_rank[a] < avg_rank[b];\n            if (ranks[0][a] != ranks[0][b]) return ranks[0][a] < ranks[0][b];\n            return a < b;\n        });\n        main_order = cells;\n        main_rank.fill(-1);\n        for (int i = 0; i < M; ++i) main_rank[main_order[i]] = i;\n\n        long long best_div = -1;\n        int best_id = 0;\n        for (int s = 0; s < 4; ++s) {\n            long long div = 0;\n            for (int v : free_ids) div += llabs((long long)ranks[s][v] - main_rank[v]);\n            if (div > best_div) {\n                best_div = div;\n                best_id = s;\n            }\n        }\n        alt_order = ords[best_id];\n        alt_rank.fill(-1);\n        for (int i = 0; i < M; ++i) alt_rank[alt_order[i]] = i;\n    }\n\n    // ---------- helpers ----------\n\n    int rank_among_remaining(const array<unsigned char, MAXV>& usd, int t) const {\n        int r = 0;\n        for (int x = 0; x < t; ++x) if (!usd[x]) ++r;\n        return r;\n    }\n\n    double skew_x(int rank, int rem) const {\n        if (rem <= 1) return 0.0;\n        if (rank <= 0) return 0.0;\n        if (rank >= rem - 1) return 1.0;\n        double x = (double)rank / (double)(rem - 1);\n        double gamma;\n        if (rem > 50) gamma = 1.75;\n        else if (rem > 35) gamma = 1.60;\n        else if (rem > 22) gamma = 1.45;\n        else gamma = 1.25;\n        double a = pow(x, gamma);\n        double b = pow(1.0 - x, gamma);\n        return a / (a + b);\n    }\n\n    int target_slot_blend(int rank, int rem, int k) const {\n        if (k <= 1 || rem <= 1) return 0;\n        double x = (double)rank / (double)(rem - 1);\n        double xs = skew_x(rank, rem);\n        double y = (rem > 20 ? (2.0 * xs + x) / 3.0 : (xs + x) / 2.0);\n        int idx = (int)llround(y * (k - 1));\n        return max(0, min(k - 1, idx));\n    }\n\n    void build_remaining_positions(\n        const array<unsigned char, MAXV>& occ,\n        array<int, MAXV>& pos_main,\n        array<int, MAXV>& pos_alt\n    ) const {\n        pos_main.fill(-1);\n        pos_alt.fill(-1);\n        int p = 0;\n        for (int v : main_order) if (!occ[v]) pos_main[v] = p++;\n        p = 0;\n        for (int v : alt_order) if (!occ[v]) pos_alt[v] = p++;\n    }\n\n    void build_legal_positions(\n        const vector<int>& legal,\n        array<int, MAXV>& lpos_main,\n        array<int, MAXV>& lpos_alt\n    ) const {\n        lpos_main.fill(-1);\n        lpos_alt.fill(-1);\n\n        vector<int> a = legal, b = legal;\n        sort(a.begin(), a.end(), [&](int x, int y) { return main_rank[x] < main_rank[y]; });\n        sort(b.begin(), b.end(), [&](int x, int y) { return alt_rank[x] < alt_rank[y]; });\n\n        for (int i = 0; i < (int)a.size(); ++i) lpos_main[a[i]] = i;\n        for (int i = 0; i < (int)b.size(); ++i) lpos_alt[b[i]] = i;\n    }\n\n    int count_legal_after_place(const array<unsigned char, MAXV>& occ, int v) const {\n        array<unsigned char, MAXV> occ2 = occ;\n        occ2[v] = 1;\n        Analysis B = analyze_empty(occ2);\n        return (int)B.legal.size();\n    }\n\n    int smallest_accessible_remove(\n        const array<unsigned char, MAXV>& occ,\n        const array<int, MAXV>& lab\n    ) const {\n        array<unsigned char, MAXV> vis{};\n        array<unsigned char, MAXV> seen_occ{};\n        int q[MAXV];\n        int qh = 0, qt = 0;\n        q[qt++] = entrance;\n        vis[entrance] = 1;\n\n        int best = -1;\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int to : nbrs[v]) {\n                if (obstacle[to]) continue;\n                if (occ[to]) {\n                    if (!seen_occ[to]) {\n                        seen_occ[to] = 1;\n                        if (best == -1 || lab[to] < lab[best]) best = to;\n                    }\n                } else if (!vis[to]) {\n                    vis[to] = 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n        return best;\n    }\n\n    long long inversion_count(const vector<int>& seq) const {\n        Fenwick fw(M);\n        long long inv = 0;\n        for (int i = (int)seq.size() - 1; i >= 0; --i) {\n            if (seq[i] > 0) inv += fw.sum_prefix(seq[i] - 1);\n            fw.add(seq[i], 1);\n        }\n        return inv;\n    }\n\n    int cheap_policy_place(\n        const array<unsigned char, MAXV>& occ,\n        const array<unsigned char, MAXV>& usd,\n        int t,\n        int empty_count\n    ) const {\n        Analysis A = analyze_empty(occ);\n        const auto& legal = A.legal;\n        if ((int)legal.size() == 1) return legal[0];\n\n        array<int, MAXV> pos_main, pos_alt, lpos_main, lpos_alt;\n        build_remaining_positions(occ, pos_main, pos_alt);\n        build_legal_positions(legal, lpos_main, lpos_alt);\n\n        int rem = empty_count - 1;\n        int r = rank_among_remaining(usd, t);\n        int tgt_all = target_slot_blend(r, rem, rem);\n        int tgt_leg = target_slot_blend(r, rem, (int)legal.size());\n        bool early = (2 * r < rem);\n\n        int best = legal[0];\n        tuple<int,int,int,int,int,int,int,int,int,int> bestKey =\n            {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX};\n\n        for (int v : legal) {\n            int dL0 = abs(lpos_main[v] - tgt_leg);\n            int dG0 = abs(pos_main[v] - tgt_all);\n            int dL1 = abs(lpos_alt[v] - tgt_leg);\n            int dG1 = abs(pos_alt[v] - tgt_all);\n            int later = (pos_main[v] > tgt_all);\n            int flex = (rem <= 20 ? count_legal_after_place(occ, v) : A.deg[v]);\n            int per = row(v) + abs(col(v) - mid);\n            int dir_bd = early ? A.block_depth[v] : -A.block_depth[v];\n            int dir_ds = early ? A.dist[v] : -A.dist[v];\n            int dir_dg = early ? -A.deg[v] : A.deg[v];\n\n            auto key = make_tuple(dL0, dG0, dL1, dG1, later, dir_bd, dir_ds, dir_dg, -flex, per);\n            if (key < bestKey) {\n                best = v;\n                bestKey = key;\n            }\n        }\n        return best;\n    }\n\n    long long evaluate_candidate(\n        int place_v,\n        int current_t,\n        const vector<vector<int>>& perms\n    ) const {\n        long long total = 0;\n\n        for (const auto& perm : perms) {\n            array<unsigned char, MAXV> occ = occupied;\n            array<int, MAXV> lab = label_at;\n            array<unsigned char, MAXV> usd = used;\n            int empty_count = current_empty_count;\n\n            occ[place_v] = 1;\n            lab[place_v] = current_t;\n            usd[current_t] = 1;\n            --empty_count;\n\n            for (int x : perm) {\n                int v = cheap_policy_place(occ, usd, x, empty_count);\n                occ[v] = 1;\n                lab[v] = x;\n                usd[x] = 1;\n                --empty_count;\n            }\n\n            vector<int> seq;\n            seq.reserve(M);\n            for (int iter = 0; iter < M; ++iter) {\n                int v = smallest_accessible_remove(occ, lab);\n                seq.push_back(lab[v]);\n                occ[v] = 0;\n            }\n            total += inversion_count(seq);\n        }\n        return total;\n    }\n\n    struct CandInfo {\n        int v;\n        long long dL0, dG0, dL1, dG1;\n        int nextLegal;\n        int later;\n        int dir_bd, dir_ds, dir_dg;\n        int per;\n        long long numeric;\n        auto key() const {\n            return make_tuple(dL0, dG0, dL1, dG1, -nextLegal, later, dir_bd, dir_ds, dir_dg, per);\n        }\n    };\n\n    int choose_place(int t, int step_idx) const {\n        int rem = current_empty_count - 1;\n        int r = rank_among_remaining(used, t);\n\n        Analysis A = analyze_empty(occupied);\n        const auto& legal = A.legal;\n\n        array<int, MAXV> pos_main, pos_alt, lpos_main, lpos_alt;\n        build_remaining_positions(occupied, pos_main, pos_alt);\n        build_legal_positions(legal, lpos_main, lpos_alt);\n\n        int tgt_all = target_slot_blend(r, rem, rem);\n        int tgt_leg = target_slot_blend(r, rem, (int)legal.size());\n        bool early = (2 * r < rem);\n\n        vector<CandInfo> pre;\n        pre.reserve(legal.size());\n\n        for (int v : legal) {\n            long long dL0 = llabs((long long)lpos_main[v] - tgt_leg);\n            long long dG0 = llabs((long long)pos_main[v] - tgt_all);\n            long long dL1 = llabs((long long)lpos_alt[v] - tgt_leg);\n            long long dG1 = llabs((long long)pos_alt[v] - tgt_all);\n            int later = (pos_main[v] > tgt_all);\n            int per = row(v) + abs(col(v) - mid);\n            int dir_bd = early ? A.block_depth[v] : -A.block_depth[v];\n            int dir_ds = early ? A.dist[v] : -A.dist[v];\n            int dir_dg = early ? -A.deg[v] : A.deg[v];\n\n            long long numeric = dL0 * 2200LL + dG0 * 450LL + dL1 * 260LL + dG1 * 80LL + later * 30LL;\n            pre.push_back({v, dL0, dG0, dL1, dG1, 0, later, dir_bd, dir_ds, dir_dg, per, numeric});\n        }\n\n        sort(pre.begin(), pre.end(), [&](const CandInfo& a, const CandInfo& b) {\n            return a.key() < b.key();\n        });\n\n        int preK = min(7, (int)pre.size());\n        vector<CandInfo> refined;\n        refined.reserve(preK);\n        for (int i = 0; i < preK; ++i) {\n            CandInfo c = pre[i];\n            c.nextLegal = count_legal_after_place(occupied, c.v);\n            c.numeric -= 4LL * c.nextLegal;\n            refined.push_back(c);\n        }\n\n        sort(refined.begin(), refined.end(), [&](const CandInfo& a, const CandInfo& b) {\n            if (a.key() != b.key()) return a.key() < b.key();\n            return a.v < b.v;\n        });\n\n        int base_best = refined[0].v;\n\n        if (rem > 42 || (int)refined.size() == 1) return base_best;\n        if ((int)refined.size() >= 2) {\n            long long gap = refined[1].numeric - refined[0].numeric;\n            if (gap >= 120) return base_best;\n        }\n\n        int candK = (rem > 28 ? min(3, (int)refined.size()) : min(4, (int)refined.size()));\n        vector<int> cand;\n        cand.reserve(candK);\n        for (int i = 0; i < candK; ++i) cand.push_back(refined[i].v);\n\n        vector<int> rem_labels;\n        rem_labels.reserve(rem - 1);\n        for (int x = 0; x < M; ++x) if (!used[x] && x != t) rem_labels.push_back(x);\n\n        int samples;\n        if (rem > 32) samples = 4;\n        else if (rem > 20) samples = 6;\n        else samples = 10;\n\n        uint64_t seed = 1469598103934665603ull;\n        seed ^= (uint64_t)(step_idx + 1) * 1099511628211ull;\n        seed ^= (uint64_t)(t + 37) * 1000003ull;\n        for (int v = 0; v < D * D; ++v) if (obstacle[v]) seed ^= (uint64_t)(v + 11) * 911382323ull;\n        XorShift64 rng(seed);\n\n        vector<vector<int>> perms;\n        perms.reserve(samples);\n        for (int s = 0; s < samples; ++s) {\n            vector<int> p = rem_labels;\n            for (int i = (int)p.size() - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(p[i], p[j]);\n            }\n            perms.push_back(move(p));\n        }\n\n        auto get_ref = [&](int v) -> const CandInfo& {\n            for (const auto& c : refined) if (c.v == v) return c;\n            return refined[0];\n        };\n\n        int best = base_best;\n        long long chosenVal = evaluate_candidate(base_best, t, perms);\n        const CandInfo* bestInfo = &get_ref(base_best);\n\n        long long switch_margin;\n        if (rem > 28) switch_margin = 4LL * samples;\n        else if (rem > 18) switch_margin = 2LL * samples;\n        else switch_margin = 1LL * samples;\n\n        for (int v : cand) {\n            if (v == base_best) continue;\n            long long val = evaluate_candidate(v, t, perms);\n            const CandInfo* info = &get_ref(v);\n            if (val + switch_margin < chosenVal ||\n                (val + switch_margin == chosenVal && info->key() < bestInfo->key())) {\n                best = v;\n                chosenVal = val;\n                bestInfo = info;\n            }\n        }\n\n        return best;\n    }\n\n    int choose_remove_actual() const {\n        return smallest_accessible_remove(occupied, label_at);\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    Solver solver(D, N);\n\n    for (int k = 0; k < N; ++k) {\n        int r, c;\n        cin >> r >> c;\n        solver.obstacle[solver.id(r, c)] = 1;\n    }\n    solver.finalize_init();\n\n    for (int step = 0; step < solver.M; ++step) {\n        int t;\n        cin >> t;\n\n        int v = solver.choose_place(t, step);\n        solver.occupied[v] = 1;\n        solver.label_at[v] = t;\n        solver.used[t] = 1;\n        --solver.current_empty_count;\n\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n' << flush;\n    }\n\n    for (int k = 0; k < solver.M; ++k) {\n        int v = solver.choose_remove_actual();\n        cout << solver.row(v) << ' ' << solver.col(v) << '\\n';\n        solver.occupied[v] = 0;\n    }\n    cout << flush;\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXC = 100;\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 DeltaPack {\n    int u[16], v[16], d[16];\n    int sz = 0;\n\n    void clear() { sz = 0; }\n\n    void add(int a, int b, int val) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < sz; i++) {\n            if (u[i] == a && v[i] == b) {\n                d[i] += val;\n                return;\n            }\n        }\n        u[sz] = a;\n        v[sz] = b;\n        d[sz] = val;\n        sz++;\n    }\n};\n\nstruct Solver {\n    int n, m;\n    int orig[MAXN][MAXN];\n    bool target[MAXC + 1][MAXC + 1]{};\n\n    int g[MAXN][MAXN];\n    int bestg[MAXN][MAXN];\n\n    int area[MAXC + 1]{};\n    int adjcnt[MAXC + 1][MAXC + 1]{};\n\n    int globalBestZero = -1;\n\n    vector<int> posCells;\n    int posIndex[MAXN * MAXN];\n\n    mt19937 rng;\n\n    static constexpr int DX[4] = {-1, 1, 0, 0};\n    static constexpr int DY[4] = {0, 0, -1, 1};\n\n    Solver() {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < n && 0 <= y && y < n;\n    }\n\n    inline int id_of(int x, int y) const {\n        return x * n + y;\n    }\n\n    void build_adj_from_board(int board[MAXN][MAXN], int cnt[MAXC + 1][MAXC + 1]) {\n        for (int i = 0; i <= m; i++) for (int j = 0; j <= m; j++) cnt[i][j] = 0;\n\n        auto add_pair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            cnt[a][b]++;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int c = board[i][j];\n                if (i == 0) add_pair(c, 0);\n                if (j == 0) add_pair(c, 0);\n                if (i + 1 < n) add_pair(c, board[i + 1][j]);\n                else add_pair(c, 0);\n                if (j + 1 < n) add_pair(c, board[i][j + 1]);\n                else add_pair(c, 0);\n            }\n        }\n    }\n\n    void init_target() {\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(orig, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = 0; j <= m; j++) target[i][j] = false;\n        }\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                target[i][j] = target[j][i] = (cnt[i][j] > 0);\n            }\n        }\n    }\n\n    void rebuild_pos_list() {\n        posCells.clear();\n        fill(posIndex, posIndex + n * n, -1);\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (g[i][j] != 0) {\n                    int id = id_of(i, j);\n                    posIndex[id] = (int)posCells.size();\n                    posCells.push_back(id);\n                }\n            }\n        }\n    }\n\n    void rebuild_state_from_current_board() {\n        for (int c = 0; c <= m; c++) area[c] = 0;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) area[g[i][j]]++;\n        build_adj_from_board(g, adjcnt);\n        rebuild_pos_list();\n    }\n\n    void reset_state_to_orig() {\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) g[i][j] = orig[i][j];\n        rebuild_state_from_current_board();\n    }\n\n    void remove_positive_id(int id) {\n        int idx = posIndex[id];\n        if (idx == -1) return;\n        int last = posCells.back();\n        posCells[idx] = last;\n        posIndex[last] = idx;\n        posCells.pop_back();\n        posIndex[id] = -1;\n    }\n\n    void save_global_best_if_improved() {\n        if (area[0] > globalBestZero) {\n            globalBestZero = area[0];\n            for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = g[i][j];\n        }\n    }\n\n    // Optimized articulation-style check:\n    // removing (x,y) disconnects color c iff its same-colored neighbors\n    // become separated in G - {(x,y)}.\n    bool can_remove_color_cell(int x, int y) {\n        int c = g[x][y];\n        if (c == 0) return false;\n        if (area[c] <= 1) return false;\n\n        pair<int,int> same[4];\n        int k = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == c) same[k++] = {nx, ny};\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        static int vis[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            stamp = 1;\n        }\n\n        bool reached[4] = {};\n        reached[0] = true;\n        int reached_cnt = 1;\n\n        queue<pair<int,int>> q;\n        q.push(same[0]);\n        vis[same[0].first][same[0].second] = stamp;\n\n        while (!q.empty() && reached_cnt < k) {\n            auto [cx, cy] = q.front();\n            q.pop();\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = cx + DX[dir], ny = cy + DY[dir];\n                if (!inside(nx, ny)) continue;\n                if (nx == x && ny == y) continue;\n                if (g[nx][ny] != c) continue;\n                if (vis[nx][ny] == stamp) continue;\n                vis[nx][ny] = stamp;\n                q.push({nx, ny});\n\n                for (int i = 1; i < k; i++) {\n                    if (!reached[i] && same[i].first == nx && same[i].second == ny) {\n                        reached[i] = true;\n                        reached_cnt++;\n                    }\n                }\n            }\n        }\n\n        return reached_cnt == k;\n    }\n\n    bool can_attach_zero(int x, int y) const {\n        if (x == 0 || x == n - 1 || y == 0 || y == n - 1) return true;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (inside(nx, ny) && g[nx][ny] == 0) return true;\n        }\n        return false;\n    }\n\n    int activity_score(int x, int y) const {\n        int c = g[x][y];\n        if (c == 0) return -100;\n        int sc = 0;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + DX[dir], ny = y + DY[dir];\n            if (!inside(nx, ny) || g[nx][ny] != c) sc++;\n        }\n        return sc;\n    }\n\n    bool check_recolor_known_removable(int x, int y, int t, int &deltaPerim, DeltaPack &pack) {\n        int c = g[x][y];\n        if (c == 0 || c == t) return false;\n\n        if (t == 0) {\n            if (!can_attach_zero(x, y)) return false;\n        } else {\n            bool touch = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (inside(nx, ny) && g[nx][ny] == t) {\n                    touch = true;\n                    break;\n                }\n            }\n            if (!touch) return false;\n        }\n\n        pack.clear();\n        deltaPerim = 0;\n\n        auto process_side = [&](int other) {\n            deltaPerim += (t != other) - (c != other);\n            pack.add(c, other, -1);\n            pack.add(t, other, +1);\n        };\n\n        if (x > 0) process_side(g[x - 1][y]);\n        else process_side(0);\n        if (x + 1 < n) process_side(g[x + 1][y]);\n        else process_side(0);\n        if (y > 0) process_side(g[x][y - 1]);\n        else process_side(0);\n        if (y + 1 < n) process_side(g[x][y + 1]);\n        else process_side(0);\n\n        for (int i = 0; i < pack.sz; i++) {\n            int a = pack.u[i], b = pack.v[i];\n            int after = adjcnt[a][b] + pack.d[i];\n            if ((after > 0) != target[a][b]) return false;\n        }\n        return true;\n    }\n\n    void apply_move(int x, int y, int t, const DeltaPack &pack) {\n        int c = g[x][y];\n        area[c]--;\n        area[t]++;\n        g[x][y] = t;\n        for (int i = 0; i < pack.sz; i++) {\n            adjcnt[pack.u[i]][pack.v[i]] += pack.d[i];\n        }\n        if (t == 0) remove_positive_id(id_of(x, y));\n    }\n\n    bool try_zero_move_known_removable(int x, int y) {\n        int dp;\n        DeltaPack pack;\n        if (!check_recolor_known_removable(x, y, 0, dp, pack)) return false;\n        apply_move(x, y, 0, pack);\n        save_global_best_if_improved();\n        return true;\n    }\n\n    void harvest_local(const vector<pair<int,int>> &seeds) {\n        static int seen[MAXN][MAXN];\n        static int stamp = 1;\n        stamp++;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n\n        queue<pair<int,int>> q;\n\n        auto push = [&](int x, int y) {\n            if (!inside(x, y)) return;\n            if (seen[x][y] == stamp) return;\n            seen[x][y] = stamp;\n            q.push({x, y});\n        };\n\n        for (auto [x, y] : seeds) {\n            for (int dx = -2; dx <= 2; dx++) {\n                for (int dy = -2; dy <= 2; dy++) {\n                    if (abs(dx) + abs(dy) <= 3) push(x + dx, y + dy);\n                }\n            }\n        }\n\n        while (!q.empty()) {\n            auto [x, y] = q.front();\n            q.pop();\n            if (!inside(x, y) || g[x][y] == 0) continue;\n            if (!can_remove_color_cell(x, y)) continue;\n            if (try_zero_move_known_removable(x, y)) {\n                push(x, y);\n                for (int dir = 0; dir < 4; dir++) {\n                    push(x + DX[dir], y + DY[dir]);\n                    push(x + 2 * DX[dir], y + 2 * DY[dir]);\n                }\n            }\n        }\n    }\n\n    int strict_sweep_once(int variant) {\n        vector<int> ord = posCells;\n        shuffle(ord.begin(), ord.end(), rng);\n\n        int changes = 0;\n\n        for (int id : ord) {\n            int x = id / n, y = id % n;\n            if (g[x][y] == 0) continue;\n\n            bool removable = can_remove_color_cell(x, y);\n            if (!removable) continue;\n\n            if (try_zero_move_known_removable(x, y)) {\n                changes++;\n                continue;\n            }\n\n            bool used[MAXC + 1] = {};\n            int bestT = -1, bestDP = 100;\n            DeltaPack bestPack;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == g[x][y] || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_recolor_known_removable(x, y, t, dp, pack)) continue;\n\n                if (dp < bestDP) {\n                    bestDP = dp;\n                    bestT = t;\n                    bestPack = pack;\n                }\n            }\n\n            if (bestT != -1) {\n                bool accept = false;\n                if (bestDP < 0) accept = true;\n                else {\n                    int zprob = (variant == 0 ? 4 : 2); // 1/4 or 1/2 for dp==0\n                    if ((bestDP == 0) && (rng() % zprob == 0)) accept = true;\n                }\n\n                if (accept) {\n                    apply_move(x, y, bestT, bestPack);\n                    harvest_local({{x, y}});\n                    changes++;\n                }\n            }\n        }\n\n        return changes;\n    }\n\n    int pick_random_positive_id(int variant) {\n        if (posCells.empty()) return -1;\n        if (posCells.size() == 1) return posCells[0];\n\n        if (variant == 0) {\n            if ((rng() % 100) < 35) {\n                int id1 = posCells[rng() % posCells.size()];\n                int id2 = posCells[rng() % posCells.size()];\n                int x1 = id1 / n, y1 = id1 % n;\n                int x2 = id2 / n, y2 = id2 % n;\n                return activity_score(x1, y1) >= activity_score(x2, y2) ? id1 : id2;\n            }\n            return posCells[rng() % posCells.size()];\n        } else {\n            return posCells[rng() % posCells.size()];\n        }\n    }\n\n    void run_search_until(double end_time, const Timer &timer, int variant) {\n        reset_state_to_orig();\n        save_global_best_if_improved();\n\n        double start = timer.elapsed();\n        double budget = max(0.0, end_time - start);\n        double greedy_part = (variant == 0 ? 0.24 : 0.16);\n        double greedy_end = min(end_time, start + budget * greedy_part);\n\n        while (timer.elapsed() < greedy_end) {\n            int ch = strict_sweep_once(variant);\n            if (ch == 0) break;\n        }\n\n        long long iter = 0;\n        long long lastImproveIter = 0;\n        int localBest = area[0];\n\n        while (timer.elapsed() < end_time) {\n            iter++;\n\n            if ((iter % 3000) == 0) {\n                int ch = strict_sweep_once(variant);\n                if (area[0] > localBest) {\n                    localBest = area[0];\n                    lastImproveIter = iter;\n                }\n                if (ch == 0 && iter - lastImproveIter > 20000) {\n                    strict_sweep_once(variant);\n                    lastImproveIter = iter;\n                }\n            }\n\n            int id = pick_random_positive_id(variant);\n            if (id == -1) break;\n            int x = id / n, y = id % n;\n            if (g[x][y] == 0) continue;\n\n            bool removable = can_remove_color_cell(x, y);\n            if (!removable) continue;\n\n            int zero_try_mask = (variant == 0 ? 7 : 5); // 1/8 or 1/6-ish via modulo below\n            if ((iter % (zero_try_mask + 1)) == 0) {\n                if (try_zero_move_known_removable(x, y)) {\n                    harvest_local({{x, y}});\n                    if (area[0] > localBest) {\n                        localBest = area[0];\n                        lastImproveIter = iter;\n                    }\n                    continue;\n                }\n            }\n\n            bool used[MAXC + 1] = {};\n            int candT[4], candDP[4], candK = 0;\n            DeltaPack candPack[4];\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + DX[dir], ny = y + DY[dir];\n                if (!inside(nx, ny)) continue;\n                int t = g[nx][ny];\n                if (t <= 0 || t == g[x][y] || used[t]) continue;\n                used[t] = true;\n\n                int dp;\n                DeltaPack pack;\n                if (!check_recolor_known_removable(x, y, t, dp, pack)) continue;\n\n                candT[candK] = t;\n                candDP[candK] = dp;\n                candPack[candK] = pack;\n                candK++;\n            }\n\n            if (candK == 0) continue;\n\n            int pick = 0;\n            int rand_pick_prob = (variant == 0 ? 35 : 50);\n            if (candK >= 2 && (rng() % 100) < rand_pick_prob) {\n                pick = rng() % candK;\n            } else {\n                for (int i = 1; i < candK; i++) {\n                    if (candDP[i] < candDP[pick]) pick = i;\n                }\n            }\n\n            int dp = candDP[pick];\n            double p = (timer.elapsed() - start) / max(1e-9, budget);\n            p = min(1.0, max(0.0, p));\n\n            double temp;\n            if (variant == 0) temp = 1.8 * (1.0 - p) + 0.03 * p;\n            else temp = 2.2 * (1.0 - p) + 0.05 * p;\n\n            bool accept = false;\n            if (dp <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-double(dp) / temp);\n                double u = (double(rng()) + 0.5) * (1.0 / 4294967296.0);\n                if (u < prob) accept = true;\n            }\n\n            if (accept) {\n                apply_move(x, y, candT[pick], candPack[pick]);\n                harvest_local({{x, y}});\n                if (area[0] > localBest) {\n                    localBest = area[0];\n                    lastImproveIter = iter;\n                }\n            }\n        }\n\n        save_global_best_if_improved();\n    }\n\n    bool full_validate(int board[MAXN][MAXN]) {\n        int cntArea[MAXC + 1] = {};\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cntArea[board[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cntArea[c] == 0) return false;\n\n        int cnt[MAXC + 1][MAXC + 1];\n        build_adj_from_board(board, cnt);\n        for (int i = 0; i <= m; i++) {\n            for (int j = i + 1; j <= m; j++) {\n                bool cur = cnt[i][j] > 0;\n                if (cur != target[i][j]) return false;\n            }\n        }\n\n        vector<vector<int>> vis(n, vector<int>(n, -1));\n        for (int c = 1; c <= m; c++) {\n            pair<int,int> st = {-1, -1};\n            for (int i = 0; i < n && st.first == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (board[i][j] == c) {\n                        st = {i, j};\n                        break;\n                    }\n                }\n            }\n            if (st.first == -1) return false;\n\n            queue<pair<int,int>> q;\n            q.push(st);\n            vis[st.first][st.second] = c;\n            int got = 0;\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + DX[dir], ny = y + DY[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != c || vis[nx][ny] == c) continue;\n                    vis[nx][ny] = c;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[c]) return false;\n        }\n\n        if (cntArea[0] > 0) {\n            vector<vector<int>> zvis(n, vector<int>(n, 0));\n            queue<pair<int,int>> q;\n            int got = 0;\n\n            for (int i = 0; i < n; i++) {\n                for (int j : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n            for (int j = 0; j < n; j++) {\n                for (int i : {0, n - 1}) {\n                    if (board[i][j] == 0 && !zvis[i][j]) {\n                        zvis[i][j] = 1;\n                        q.push({i, j});\n                    }\n                }\n            }\n\n            while (!q.empty()) {\n                auto [x, y] = q.front();\n                q.pop();\n                got++;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + DX[dir], ny = y + DY[dir];\n                    if (!inside(nx, ny)) continue;\n                    if (board[nx][ny] != 0 || zvis[nx][ny]) continue;\n                    zvis[nx][ny] = 1;\n                    q.push({nx, ny});\n                }\n            }\n            if (got != cntArea[0]) return false;\n        }\n\n        return true;\n    }\n\n    void solve() {\n        cin >> n >> m;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) cin >> orig[i][j];\n        }\n\n        init_target();\n\n        // Fallback = original board\n        globalBestZero = -1;\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) bestg[i][j] = orig[i][j];\n\n        Timer timer;\n        const double TL = 1.92;\n\n        double t1 = min(TL - 0.20, TL * 0.68);\n        if (t1 < 0.5) t1 = TL * 0.75;\n\n        run_search_until(t1, timer, 0);\n        if (timer.elapsed() < TL - 0.01) {\n            run_search_until(TL - 0.002, timer, 1);\n        }\n\n        if (!full_validate(bestg)) {\n            for (int i = 0; i < n; i++) {\n                for (int j = 0; j < n; j++) {\n                    cout << orig[i][j] << (j + 1 == n ? '\\n' : ' ');\n                }\n            }\n            return;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                cout << bestg[i][j] << (j + 1 == n ? '\\n' : ' ');\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Bin {\n    vector<int> items;\n    long double est_load = 0;\n};\n\nstruct Plan {\n    bool exact_all = false;\n    int rounds = 0;\n    int C = 0;  // exact-sorted prefix length\n    int K = 0;  // total prefix length handled with actual bin insertion\n    long double util = -1e100L;\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int lgD = 0;\n\n    vector<int> insc;\n    vector<long double> H, est_pos, pref;\n    vector<long double> est_item;\n    vector<vector<signed char>> cache; // 2 unknown, -1,0,1\n    vector<uint64_t> keyv;\n\n    static int ceil_log2_int(int x) {\n        int k = 0, p = 1;\n        while (p < x) p <<= 1, ++k;\n        return k;\n    }\n\n    static 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    int remain() const { return Q - used; }\n\n    int ask_raw(const vector<int>& L, const vector<int>& R) {\n        // Safety: should never happen after planning fix.\n        // But never exceed Q queries.\n        if (used >= Q) {\n            // Fallback behavior: impossible in correct logic.\n            // Return estimated equality-ish direction to avoid extra output.\n            return 0;\n        }\n\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        cin >> s;\n        ++used;\n        if (s == \"<\") return -1;\n        if (s == \">\") return 1;\n        return 0;\n    }\n\n    int cmp_item(int a, int b) {\n        if (cache[a][b] != 2) return cache[a][b];\n        vector<int> L{a}, R{b};\n        int c = ask_raw(L, R);\n        cache[a][b] = (signed char)c;\n        cache[b][a] = (signed char)(-c);\n        return c;\n    }\n\n    int cmp_sets(const vector<int>& A, const vector<int>& B) {\n        if (A.size() == 1 && B.size() == 1) return cmp_item(A[0], B[0]);\n        return ask_raw(A, B);\n    }\n\n    long double pref_val(int k) const {\n        k = max(0, min(k, N));\n        return pref[k];\n    }\n\n    vector<int> exact_sort_items(const vector<int>& items) {\n        // descending: heavier first\n        vector<int> sorted;\n        sorted.reserve(items.size());\n        for (int x : items) {\n            int l = 0, r = (int)sorted.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = cmp_item(x, sorted[m]);\n                if (c > 0) r = m;\n                else l = m + 1;\n            }\n            sorted.insert(sorted.begin() + l, x);\n        }\n        return sorted;\n    }\n\n    vector<int> swiss_order(int rounds) {\n        vector<int> score(N, 0);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return keyv[a] < keyv[b];\n        });\n\n        for (int r = 0; r < rounds; ++r) {\n            uint64_t salt = splitmix64(123456789ULL + 1000003ULL * r + 911ULL * N + 3571ULL * D + 8191ULL * Q);\n\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (score[a] != score[b]) return score[a] > score[b];\n                return (keyv[a] ^ salt) < (keyv[b] ^ salt);\n            });\n\n            for (int i = 0; i + 1 < N; i += 2) {\n                int a = ord[i], b = ord[i + 1];\n                int c = cmp_item(a, b);\n                if (c > 0) {\n                    ++score[a];\n                    --score[b];\n                } else if (c < 0) {\n                    ++score[b];\n                    --score[a];\n                }\n            }\n        }\n\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return keyv[a] < keyv[b];\n        });\n\n        return ord;\n    }\n\n    Plan choose_plan() {\n        Plan best;\n        int pair_round_cost = N / 2;\n\n        // Exact-all plan\n        if (insc[N] <= Q) {\n            int K = min(N, D + (Q - insc[N]) / max(1, lgD));\n            long double util =\n                1.00L * pref_val(N) +\n                0.60L * (pref_val(K) - pref_val(D));\n            best = {true, 0, N, K, util};\n        }\n\n        // Swiss + exact prefix + actual insertion prefix\n        int Rmax = (pair_round_cost == 0 ? 0 : min(8, Q / pair_round_cost));\n        for (int R = 1; R <= Rmax; ++R) {\n            int rem_after_rounds = Q - R * pair_round_cost;\n            if (rem_after_rounds < 0) continue;\n\n            long double coarse_coef = min((long double)0.68L, (long double)(0.28L + 0.07L * R));\n\n            for (int C = D; C <= N; ++C) {\n                if (insc[C] > rem_after_rounds) break;\n\n                int rem_after_exact = rem_after_rounds - insc[C];\n                int K = min(N, D + rem_after_exact / max(1, lgD));\n\n                long double util =\n                    1.00L * pref_val(C) +\n                    coarse_coef * max((long double)0.0L, pref_val(K) - pref_val(C)) +\n                    0.012L * R * pref_val(N);\n\n                if (util > best.util) {\n                    best = {false, R, C, K, util};\n                }\n            }\n        }\n\n        // Very conservative fallback\n        if (best.util < -1e50L) {\n            int C = D;\n            int K = D;\n            best = {false, 1, C, K, 0};\n        }\n\n        return best;\n    }\n\n    int compare_bins_est(const Bin& a, const Bin& b) {\n        if (a.est_load < b.est_load) return -1;\n        if (a.est_load > b.est_load) return 1;\n        return 0;\n    }\n\n    void insert_bin_sorted_maybe_actual(vector<Bin>& bins, Bin cur) {\n        if (bins.empty()) {\n            bins.push_back(std::move(cur));\n            return;\n        }\n\n        // Safety fallback: if somehow no queries remain, use estimated order.\n        if (remain() <= 0) {\n            int l = 0, r = (int)bins.size();\n            while (l < r) {\n                int m = (l + r) >> 1;\n                int c = compare_bins_est(cur, bins[m]);\n                if (c <= 0) r = m;\n                else l = m + 1;\n            }\n            bins.insert(bins.begin() + l, std::move(cur));\n            return;\n        }\n\n        int l = 0, r = (int)bins.size();\n        while (l < r) {\n            // Another safety fallback inside binary search\n            if (remain() <= 0) {\n                int ll = 0, rr = (int)bins.size();\n                while (ll < rr) {\n                    int m = (ll + rr) >> 1;\n                    int c = compare_bins_est(cur, bins[m]);\n                    if (c <= 0) rr = m;\n                    else ll = m + 1;\n                }\n                bins.insert(bins.begin() + ll, std::move(cur));\n                return;\n            }\n\n            int m = (l + r) >> 1;\n            int c = cmp_sets(cur.items, bins[m].items);\n            if (c <= 0) r = m;\n            else l = m + 1;\n        }\n        bins.insert(bins.begin() + l, std::move(cur));\n    }\n\n    vector<Bin> actual_assign_prefix(const vector<int>& order, int K) {\n        // Requires top D items of order to be exact descending.\n        vector<Bin> bins;\n        bins.reserve(D);\n        if (K < D) return bins;\n\n        // Initialize bins in ascending actual order by reversing exact top D.\n        for (int j = 0; j < D; ++j) {\n            Bin b;\n            int item = order[D - 1 - j];\n            b.items.push_back(item);\n            b.est_load = est_item[item];\n            bins.push_back(std::move(b));\n        }\n\n        for (int p = D; p < K; ++p) {\n            Bin cur = std::move(bins.front());\n            bins.erase(bins.begin());\n\n            int item = order[p];\n            cur.items.push_back(item);\n            cur.est_load += est_item[item];\n\n            insert_bin_sorted_maybe_actual(bins, std::move(cur));\n        }\n        return bins;\n    }\n\n    vector<Bin> estimated_assign_rest(const vector<int>& order, int start, vector<Bin> bins) {\n        if (bins.empty()) bins.assign(D, Bin());\n\n        for (int p = start; p < N; ++p) {\n            int best = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load < bins[best].est_load) best = j;\n            }\n            int item = order[p];\n            bins[best].items.push_back(item);\n            bins[best].est_load += est_item[item];\n        }\n        return bins;\n    }\n\n    static void erase_one(vector<int>& v, int x) {\n        for (int i = 0; i < (int)v.size(); ++i) {\n            if (v[i] == x) {\n                v.erase(v.begin() + i);\n                return;\n            }\n        }\n    }\n\n    void local_improve(vector<Bin>& bins, const vector<char>& fixed) {\n        for (int iter = 0; iter < 400; ++iter) {\n            int hi = 0, lo = 0;\n            for (int j = 1; j < D; ++j) {\n                if (bins[j].est_load > bins[hi].est_load) hi = j;\n                if (bins[j].est_load < bins[lo].est_load) lo = j;\n            }\n            if (hi == lo) break;\n\n            long double A = bins[hi].est_load;\n            long double B = bins[lo].est_load;\n            long double best_diff = fabsl(A - B);\n\n            int type = 0; // 1 move, 2 swap\n            int bx = -1, by = -1;\n\n            if ((int)bins[hi].items.size() > 1) {\n                for (int x : bins[hi].items) {\n                    if (fixed[x]) continue;\n                    long double w = est_item[x];\n                    long double nd = fabsl((A - w) - (B + w));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 1;\n                        bx = x;\n                    }\n                }\n            }\n\n            for (int x : bins[hi].items) {\n                if (fixed[x]) continue;\n                long double wx = est_item[x];\n                for (int y : bins[lo].items) {\n                    if (fixed[y]) continue;\n                    long double wy = est_item[y];\n                    long double nd = fabsl((A - wx + wy) - (B - wy + wx));\n                    if (nd + 1e-18L < best_diff) {\n                        best_diff = nd;\n                        type = 2;\n                        bx = x;\n                        by = y;\n                    }\n                }\n            }\n\n            if (type == 0) break;\n\n            if (type == 1) {\n                erase_one(bins[hi].items, bx);\n                bins[lo].items.push_back(bx);\n                long double w = est_item[bx];\n                bins[hi].est_load -= w;\n                bins[lo].est_load += w;\n            } else {\n                erase_one(bins[hi].items, bx);\n                erase_one(bins[lo].items, by);\n                bins[hi].items.push_back(by);\n                bins[lo].items.push_back(bx);\n                long double wx = est_item[bx];\n                long double wy = est_item[by];\n                bins[hi].est_load += wy - wx;\n                bins[lo].est_load += wx - wy;\n            }\n        }\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        lgD = ceil_log2_int(D);\n\n        insc.assign(N + 1, 0);\n        for (int k = 2; k <= N; ++k) insc[k] = insc[k - 1] + ceil_log2_int(k);\n\n        H.assign(N + 1, 0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0L / i;\n\n        est_pos.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_pos[p] = H[N] - H[p];\n\n        pref.assign(N + 1, 0);\n        for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + est_pos[i];\n\n        cache.assign(N, vector<signed char>(N, 2));\n        for (int i = 0; i < N; ++i) cache[i][i] = 0;\n\n        keyv.resize(N);\n        for (int i = 0; i < N; ++i) {\n            keyv[i] = splitmix64((uint64_t)(i + 1) * 1234567ULL + 10007ULL * N + 1000003ULL * D + 998244353ULL * Q);\n        }\n\n        Plan plan = choose_plan();\n\n        vector<int> order;\n        int C = 0;\n        int K = 0;\n\n        if (plan.exact_all) {\n            vector<int> all(N);\n            iota(all.begin(), all.end(), 0);\n            order = exact_sort_items(all);\n            C = N;\n            K = min(plan.K, N);\n        } else {\n            vector<int> coarse = swiss_order(plan.rounds);\n\n            vector<int> prefix(coarse.begin(), coarse.begin() + plan.C);\n            vector<int> exact_prefix = exact_sort_items(prefix);\n\n            order.reserve(N);\n            for (int x : exact_prefix) order.push_back(x);\n            for (int i = plan.C; i < N; ++i) order.push_back(coarse[i]);\n\n            C = plan.C;\n            K = min(plan.K, N);\n        }\n\n        est_item.assign(N, 0);\n        for (int p = 0; p < N; ++p) est_item[order[p]] = est_pos[p];\n\n        // Extra safety: recompute a conservative feasible K from actual remaining budget.\n        // Cost of actual insertion from D..K-1 is (K-D)*lgD.\n        if (C >= D) {\n            int safeK = min(N, D + remain() / max(1, lgD));\n            K = min(K, safeK);\n        } else {\n            K = 0;\n        }\n\n        vector<char> fixed(N, 0);\n        for (int p = 0; p < C; ++p) fixed[order[p]] = 1;\n\n        vector<Bin> bins;\n        if (K >= D) {\n            bins = actual_assign_prefix(order, K);\n            bins = estimated_assign_rest(order, K, std::move(bins));\n        } else {\n            bins = estimated_assign_rest(order, 0, {});\n        }\n\n        local_improve(bins, fixed);\n\n        while (used < Q) {\n            vector<int> L{0}, R{1};\n            ask_raw(L, R);\n        }\n\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b].items) ans[x] = b;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Policy {\n    int max_chunks = 4;\n    int shortlist = 20;\n    int boundary_B = 7;\n\n    int move_pen = 14;\n    int seg_inv_w = 3;\n    int seg_adj_w = 9;\n\n    int dest_inv_w = 7;\n    int fit_w = 3;\n    int top_w = 2;\n    int size_w = 1;\n    int empty_bonus = 20;\n    int bad_fit_base = 24;\n    int bad_fit_mul = 3;\n\n    int final_move_w = 340;\n    int final_assign_w = 1;\n    int final_global_w = 6;\n    int final_future_w = 28;\n    int final_future2_w = 6;\n    int final_empty_shortage_w = 180;\n    int final_removed_bonus = 420;\n    int future_depth = 4;\n\n    int gen_pen1 = 4;\n    int gen_pen2 = 7;\n    int gen_pen3 = 9;\n    bool use_dec_runs = true;\n\n    bool try_reuse_assignment = true;\n    int reuse_expand_masks = 2;\n    int reuse_variants = 1;\n};\n\nstruct Result {\n    long long energy;\n    vector<pair<int,int>> ops;\n};\n\nstruct Simulator {\n    int n, m;\n    vector<vector<int>> init_st;\n\n    Simulator(int n_, int m_, const vector<vector<int>>& st_) : n(n_), m(m_), init_st(st_) {}\n\n    static 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    static bool same_policy(const Policy& a, const Policy& b) {\n        return\n            a.max_chunks == b.max_chunks &&\n            a.shortlist == b.shortlist &&\n            a.boundary_B == b.boundary_B &&\n            a.move_pen == b.move_pen &&\n            a.seg_inv_w == b.seg_inv_w &&\n            a.seg_adj_w == b.seg_adj_w &&\n            a.dest_inv_w == b.dest_inv_w &&\n            a.fit_w == b.fit_w &&\n            a.top_w == b.top_w &&\n            a.size_w == b.size_w &&\n            a.empty_bonus == b.empty_bonus &&\n            a.bad_fit_base == b.bad_fit_base &&\n            a.bad_fit_mul == b.bad_fit_mul &&\n            a.final_move_w == b.final_move_w &&\n            a.final_assign_w == b.final_assign_w &&\n            a.final_global_w == b.final_global_w &&\n            a.final_future_w == b.final_future_w &&\n            a.final_future2_w == b.final_future2_w &&\n            a.final_empty_shortage_w == b.final_empty_shortage_w &&\n            a.final_removed_bonus == b.final_removed_bonus &&\n            a.future_depth == b.future_depth &&\n            a.gen_pen1 == b.gen_pen1 &&\n            a.gen_pen2 == b.gen_pen2 &&\n            a.gen_pen3 == b.gen_pen3 &&\n            a.use_dec_runs == b.use_dec_runs &&\n            a.try_reuse_assignment == b.try_reuse_assignment &&\n            a.reuse_expand_masks == b.reuse_expand_masks &&\n            a.reuse_variants == b.reuse_variants;\n    }\n\n    int urgency(int x, int cur) const {\n        int d = x - cur;\n        if (d <= 10) return 5;\n        if (d <= 20) return 4;\n        if (d <= 40) return 3;\n        if (d <= 80) return 2;\n        return 1;\n    }\n\n    void remove_possible(vector<vector<int>>& st, vector<pair<int,int>>& ops, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ops.push_back({cur, 0});\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    void remove_possible_state_only(vector<vector<int>>& st, int& cur) const {\n        while (cur <= n) {\n            bool found = false;\n            for (int i = 0; i < m; i++) {\n                if (!st[i].empty() && st[i].back() == cur) {\n                    st[i].pop_back();\n                    ++cur;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) break;\n        }\n    }\n\n    pair<int,int> find_box(const vector<vector<int>>& st, int v) const {\n        for (int i = 0; i < m; 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    int count_empty(const vector<vector<int>>& st) const {\n        int c = 0;\n        for (const auto& s : st) if (s.empty()) c++;\n        return c;\n    }\n\n    long long cross_inv_cost(const vector<int>& dst, const vector<int>& chunk, int cur) const {\n        long long c = 0;\n        for (int x : dst) {\n            int w = urgency(x, cur);\n            for (int y : chunk) {\n                if (x < y) c += w;\n            }\n        }\n        return c;\n    }\n\n    long long destination_local_cost(const vector<vector<int>>& st, int d, const vector<int>& chunk, int cur, const Policy& P) const {\n        int chunk_bottom = chunk.front();\n        long long c = 0;\n        c += 1LL * P.dest_inv_w * cross_inv_cost(st[d], chunk, cur);\n        c += 1LL * P.size_w * (int)st[d].size();\n\n        if (st[d].empty()) {\n            c -= P.empty_bonus;\n        } else {\n            int top = st[d].back();\n            int fit_pen = 0;\n            if (top > chunk_bottom) fit_pen = top - chunk_bottom;\n            else fit_pen = P.bad_fit_base + P.bad_fit_mul * (chunk_bottom - top);\n            c += 1LL * P.fit_w * fit_pen;\n\n            int soon = max(0, 30 - (top - cur));\n            c += 1LL * P.top_w * soon;\n        }\n        return c;\n    }\n\n    vector<pair<int,int>> decode_mask(int t, uint32_t mask) const {\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if ((mask >> i) & 1U) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n        return segs;\n    }\n\n    uint32_t encode_segs(const vector<pair<int,int>>& segs) const {\n        uint32_t mask = 0;\n        for (int i = 0; i + 1 < (int)segs.size(); i++) {\n            mask |= (1U << segs[i].second);\n        }\n        return mask;\n    }\n\n    uint32_t partition_by_metric(const vector<vector<long long>>& metric, int t, int max_chunks, int pen) const {\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> dp(max_chunks + 1, vector<long long>(t + 1, INF));\n        vector<vector<int>> prv(max_chunks + 1, vector<int>(t + 1, -1));\n        dp[0][0] = 0;\n        for (int k = 1; k <= max_chunks; k++) {\n            for (int i = 1; i <= t; i++) {\n                for (int l = 0; l < i; l++) {\n                    if (dp[k - 1][l] == INF) continue;\n                    long long cand = dp[k - 1][l] + metric[l][i - 1] + pen;\n                    if (cand < dp[k][i]) {\n                        dp[k][i] = cand;\n                        prv[k][i] = l;\n                    }\n                }\n            }\n        }\n        int best_k = 1;\n        long long best = dp[1][t];\n        for (int k = 2; k <= max_chunks; k++) {\n            if (dp[k][t] < best) {\n                best = dp[k][t];\n                best_k = k;\n            }\n        }\n        vector<pair<int,int>> rev;\n        int i = t, k = best_k;\n        while (k > 0) {\n            int l = prv[k][i];\n            rev.push_back({l, i - 1});\n            i = l;\n            --k;\n        }\n        reverse(rev.begin(), rev.end());\n        return encode_segs(rev);\n    }\n\n    uint32_t decreasing_runs_mask(const vector<int>& b, int max_chunks,\n                                  const vector<vector<long long>>& merge_metric) const {\n        int t = (int)b.size();\n        vector<pair<int,int>> segs;\n        int l = 0;\n        for (int i = 0; i + 1 < t; i++) {\n            if (b[i] < b[i + 1]) {\n                segs.push_back({l, i});\n                l = i + 1;\n            }\n        }\n        segs.push_back({l, t - 1});\n\n        while ((int)segs.size() > max_chunks) {\n            long long best_add = (1LL << 60);\n            int best_i = -1;\n            for (int i = 0; i + 1 < (int)segs.size(); i++) {\n                int l0 = segs[i].first;\n                int r0 = segs[i].second;\n                int l1 = segs[i + 1].first;\n                int r1 = segs[i + 1].second;\n                long long add = merge_metric[l0][r1] - merge_metric[l0][r0] - merge_metric[l1][r1];\n                if (add < best_add) {\n                    best_add = add;\n                    best_i = i;\n                }\n            }\n            segs[best_i].second = segs[best_i + 1].second;\n            segs.erase(segs.begin() + best_i + 1);\n        }\n        return encode_segs(segs);\n    }\n\n    bool assign_unique_destinations(\n        const vector<vector<int>>& st,\n        int src,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        vector<int>& dest_of_seg,\n        long long& min_cost\n    ) const {\n        int k = (int)segs.size();\n        vector<int> dests;\n        for (int d = 0; d < m; d++) if (d != src) dests.push_back(d);\n        int D = (int)dests.size();\n        if (k > D) return false;\n\n        const long long INF = (1LL << 60);\n        vector<vector<long long>> cost(k, vector<long long>(D, INF));\n\n        for (int sidx = 0; sidx < k; sidx++) {\n            int l = segs[sidx].first, r = segs[sidx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n            for (int di = 0; di < D; di++) {\n                int d = dests[di];\n                cost[sidx][di] = destination_local_cost(st, d, chunk, cur, P);\n            }\n        }\n\n        int FULL = 1 << D;\n        vector<vector<long long>> dp(k + 1, vector<long long>(FULL, INF));\n        vector<vector<int>> prv_mask(k + 1, vector<int>(FULL, -1));\n        vector<vector<int>> prv_dst(k + 1, vector<int>(FULL, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < k; i++) {\n            for (int mask = 0; mask < FULL; mask++) {\n                if (dp[i][mask] == INF) continue;\n                for (int di = 0; di < D; di++) {\n                    if ((mask >> di) & 1) continue;\n                    long long cand = dp[i][mask] + cost[i][di];\n                    int nmask = mask | (1 << di);\n                    if (cand < dp[i + 1][nmask]) {\n                        dp[i + 1][nmask] = cand;\n                        prv_mask[i + 1][nmask] = mask;\n                        prv_dst[i + 1][nmask] = di;\n                    }\n                }\n            }\n        }\n\n        min_cost = INF;\n        int best_mask = -1;\n        for (int mask = 0; mask < FULL; mask++) {\n            if (dp[k][mask] < min_cost) {\n                min_cost = dp[k][mask];\n                best_mask = mask;\n            }\n        }\n        if (best_mask == -1) return false;\n\n        dest_of_seg.assign(k, -1);\n        int mask = best_mask;\n        for (int i = k; i >= 1; i--) {\n            int di = prv_dst[i][mask];\n            dest_of_seg[i - 1] = dests[di];\n            mask = prv_mask[i][mask];\n        }\n        return true;\n    }\n\n    struct AssignPlan {\n        vector<int> dests;\n        long long cost = 0;\n    };\n\n    vector<pair<long long,int>> sorted_dests_for_chunk(\n        const vector<vector<int>>& st,\n        int src,\n        const vector<int>& chunk,\n        int cur,\n        const Policy& P\n    ) const {\n        vector<pair<long long,int>> cand;\n        cand.reserve(m - 1);\n        for (int d = 0; d < m; d++) {\n            if (d == src) continue;\n            cand.push_back({destination_local_cost(st, d, chunk, cur, P), d});\n        }\n        sort(cand.begin(), cand.end());\n        return cand;\n    }\n\n    bool run_reuse_with_forced_choice(\n        const vector<vector<int>>& st,\n        int src,\n        int pos,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        int forced_idx,\n        int forced_dst,\n        AssignPlan& plan\n    ) const {\n        vector<vector<int>> tmp = st;\n        int k = (int)segs.size();\n        vector<int> dest_of_seg(k, -1);\n        long long total_cost = 0;\n\n        for (int idx = k - 1; idx >= 0; idx--) {\n            int l = segs[idx].first, r = segs[idx].second;\n            vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n\n            auto cand = sorted_dests_for_chunk(tmp, src, chunk, cur, P);\n            if (cand.empty()) return false;\n\n            int chosen_dst = -1;\n            long long chosen_cost = (1LL << 60);\n\n            if (idx == forced_idx) {\n                for (auto [c, d] : cand) {\n                    if (d == forced_dst) {\n                        chosen_dst = d;\n                        chosen_cost = c;\n                        break;\n                    }\n                }\n                if (chosen_dst == -1) return false;\n            } else {\n                chosen_cost = cand[0].first;\n                chosen_dst = cand[0].second;\n            }\n\n            dest_of_seg[idx] = chosen_dst;\n            total_cost += chosen_cost;\n\n            int start = pos + 1 + l;\n            vector<int> seg(tmp[src].begin() + start, tmp[src].end());\n            tmp[src].erase(tmp[src].begin() + start, tmp[src].end());\n            tmp[chosen_dst].insert(tmp[chosen_dst].end(), seg.begin(), seg.end());\n        }\n\n        plan.dests = move(dest_of_seg);\n        plan.cost = total_cost;\n        return true;\n    }\n\n    vector<AssignPlan> greedy_reuse_assignment_variants(\n        const vector<vector<int>>& st,\n        int src,\n        int pos,\n        int cur,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& blockers,\n        const Policy& P,\n        int extra_variants\n    ) const {\n        vector<AssignPlan> res;\n\n        AssignPlan base;\n        if (!run_reuse_with_forced_choice(st, src, pos, cur, segs, blockers, P, -1, -1, base)) {\n            return res;\n        }\n        res.push_back(base);\n\n        if (extra_variants <= 0) return res;\n\n        struct AltSpec {\n            long long delta;\n            int idx;\n            int dst;\n        };\n        vector<AltSpec> specs;\n\n        {\n            vector<vector<int>> tmp = st;\n            int k = (int)segs.size();\n\n            for (int idx = k - 1; idx >= 0; idx--) {\n                int l = segs[idx].first, r = segs[idx].second;\n                vector<int> chunk(blockers.begin() + l, blockers.begin() + r + 1);\n                auto cand = sorted_dests_for_chunk(tmp, src, chunk, cur, P);\n                if (!cand.empty()) {\n                    int limit = min(2, (int)cand.size());\n                    for (int t = 1; t < limit; t++) {\n                        specs.push_back({cand[t].first - cand[0].first, idx, cand[t].second});\n                    }\n\n                    int chosen_dst = cand[0].second;\n                    int start = pos + 1 + l;\n                    vector<int> seg(tmp[src].begin() + start, tmp[src].end());\n                    tmp[src].erase(tmp[src].begin() + start, tmp[src].end());\n                    tmp[chosen_dst].insert(tmp[chosen_dst].end(), seg.begin(), seg.end());\n                }\n            }\n        }\n\n        sort(specs.begin(), specs.end(), [](const AltSpec& a, const AltSpec& b) {\n            if (a.delta != b.delta) return a.delta < b.delta;\n            if (a.idx != b.idx) return a.idx < b.idx;\n            return a.dst < b.dst;\n        });\n\n        auto code_of = [&](const vector<int>& ds) -> uint64_t {\n            uint64_t x = 0;\n            for (int d : ds) x = x * 11 + (uint64_t)(d + 1);\n            return x;\n        };\n\n        unordered_set<uint64_t> used;\n        used.reserve(4);\n        used.insert(code_of(base.dests));\n\n        for (const auto& sp : specs) {\n            if ((int)res.size() >= 1 + extra_variants) break;\n            AssignPlan cand;\n            if (!run_reuse_with_forced_choice(st, src, pos, cur, segs, blockers, P, sp.idx, sp.dst, cand)) continue;\n            uint64_t code = code_of(cand.dests);\n            if (used.insert(code).second) {\n                res.push_back(move(cand));\n            }\n        }\n\n        return res;\n    }\n\n    long long global_potential(const vector<vector<int>>& st, int cur) const {\n        long long p = 0;\n        for (const auto& s : st) {\n            int h = (int)s.size();\n            for (int i = 0; i < h; i++) {\n                int w = urgency(s[i], cur);\n                for (int j = i + 1; j < h; j++) {\n                    if (s[i] < s[j]) p += w;\n                }\n            }\n        }\n        return p;\n    }\n\n    pair<long long,long long> future_blockers_score(const vector<vector<int>>& st, int cur, int depth) const {\n        long long lin = 0, quad = 0;\n        for (int z = cur; z <= n && z < cur + depth; z++) {\n            auto [si, pos] = find_box(st, z);\n            int blockers = (int)st[si].size() - pos - 1;\n            int w = depth - (z - cur);\n            lin += 1LL * w * blockers;\n            quad += 1LL * w * blockers * blockers;\n        }\n        return {lin, quad};\n    }\n\n    long long structural_cost(\n        uint32_t mask,\n        int t,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        auto segs = decode_mask(t, mask);\n        int k = (int)segs.size();\n        long long inv = 0, adj = 0;\n        for (auto [l, r] : segs) {\n            inv += invw[l][r];\n            adj += adjw[l][r];\n        }\n        return 1LL * P.move_pen * k + 1LL * P.seg_inv_w * inv + 1LL * P.seg_adj_w * adj;\n    }\n\n    vector<uint32_t> generate_candidate_masks(\n        const vector<int>& blockers,\n        const vector<vector<long long>>& invw,\n        const vector<vector<long long>>& adjw,\n        const Policy& P\n    ) const {\n        int t = (int)blockers.size();\n        vector<uint32_t> masks;\n        masks.push_back(0);\n\n        if (P.use_dec_runs) {\n            masks.push_back(decreasing_runs_mask(blockers, P.max_chunks, invw));\n        }\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen1));\n        masks.push_back(partition_by_metric(invw, t, P.max_chunks, P.gen_pen2));\n        masks.push_back(partition_by_metric(adjw, t, P.max_chunks, P.gen_pen3));\n\n        if (t >= 2) {\n            vector<pair<int,int>> candB;\n            for (int i = 0; i + 1 < t; i++) {\n                int rise = max(0, blockers[i + 1] - blockers[i]);\n                int small_bonus = max(0, 120 - blockers[i + 1]);\n                int score = 4 * rise + small_bonus;\n                candB.push_back({score, i});\n            }\n            sort(candB.begin(), candB.end(), [&](auto a, auto b) {\n                if (a.first != b.first) return a.first > b.first;\n                return a.second < b.second;\n            });\n            int B = min(P.boundary_B, (int)candB.size());\n            vector<int> idxs;\n            for (int i = 0; i < B; i++) idxs.push_back(candB[i].second);\n\n            int FULL = 1 << B;\n            for (int s = 1; s < FULL; s++) {\n                if (__builtin_popcount((unsigned)s) > P.max_chunks - 1) continue;\n                uint32_t mask = 0;\n                for (int i = 0; i < B; i++) {\n                    if ((s >> i) & 1) mask |= (1U << idxs[i]);\n                }\n                masks.push_back(mask);\n            }\n        }\n\n        sort(masks.begin(), masks.end());\n        masks.erase(unique(masks.begin(), masks.end()), masks.end());\n\n        vector<pair<long long,uint32_t>> scored;\n        scored.reserve(masks.size());\n        for (uint32_t mask : masks) {\n            auto segs = decode_mask(t, mask);\n            int k = (int)segs.size();\n            if (k > P.max_chunks || k > m - 1) continue;\n            scored.push_back({structural_cost(mask, t, invw, adjw, P), mask});\n        }\n\n        sort(scored.begin(), scored.end());\n        vector<uint32_t> res;\n        int keep = min(P.shortlist, (int)scored.size());\n        for (int i = 0; i < keep; i++) res.push_back(scored[i].second);\n        return res;\n    }\n\n    struct EvalCand {\n        long long score = (1LL << 60);\n        long long assign_cost = 0;\n        vector<pair<int,int>> segs;\n        vector<int> dests;\n    };\n\n    void evaluate_assignment(\n        const vector<vector<int>>& st,\n        int cur,\n        int src,\n        int pos,\n        const vector<pair<int,int>>& segs,\n        const vector<int>& dests,\n        long long assign_cost,\n        const Policy& P,\n        XorShift64& rng,\n        EvalCand& best\n    ) const {\n        vector<vector<int>> st2 = st;\n        int old_cur = cur;\n\n        for (int idx = (int)segs.size() - 1; idx >= 0; idx--) {\n            int l = segs[idx].first;\n            int start = pos + 1 + l;\n            int dst = dests[idx];\n\n            vector<int> seg(st2[src].begin() + start, st2[src].end());\n            st2[src].erase(st2[src].begin() + start, st2[src].end());\n            st2[dst].insert(st2[dst].end(), seg.begin(), seg.end());\n        }\n\n        int cur2 = cur;\n        remove_possible_state_only(st2, cur2);\n\n        int t = (int)st[src].size() - pos - 1;\n        int immediate_energy = t + (int)segs.size();\n        int extra_removed = (cur2 - old_cur) - 1;\n        long long gp = global_potential(st2, cur2);\n        auto [fb1, fb2] = future_blockers_score(st2, cur2, P.future_depth);\n\n        int empty_cnt = count_empty(st2);\n        int need_empty = 0;\n        if (cur2 <= 110) need_empty = 2;\n        else if (cur2 <= 170) need_empty = 1;\n        int empty_shortage = max(0, need_empty - empty_cnt);\n\n        long long score = 0;\n        score += 1LL * P.final_move_w * immediate_energy;\n        score += 1LL * P.final_assign_w * assign_cost;\n        score += 1LL * P.final_global_w * gp;\n        score += 1LL * P.final_future_w * fb1;\n        score += 1LL * P.final_future2_w * fb2;\n        score += 1LL * P.final_empty_shortage_w * empty_shortage;\n        score -= 1LL * P.final_removed_bonus * extra_removed;\n        score += rng.next_int(0, 2);\n\n        if (score < best.score) {\n            best.score = score;\n            best.assign_cost = assign_cost;\n            best.segs = segs;\n            best.dests = dests;\n        }\n    }\n\n    EvalCand choose_best_action(\n        const vector<vector<int>>& st,\n        int cur,\n        int src,\n        int pos,\n        const vector<int>& blockers,\n        const Policy& P,\n        XorShift64& rng\n    ) const {\n        int t = (int)blockers.size();\n\n        vector<vector<long long>> invw(t, vector<long long>(t, 0));\n        vector<vector<long long>> adjw(t, vector<long long>(t, 0));\n\n        for (int l = 0; l < t; l++) {\n            long long inv = 0, adj = 0;\n            for (int r = l; r < t; r++) {\n                if (r > l && blockers[r - 1] < blockers[r]) adj++;\n                for (int i = l; i < r; i++) {\n                    if (blockers[i] < blockers[r]) inv += urgency(blockers[i], cur);\n                }\n                invw[l][r] = inv;\n                adjw[l][r] = adj;\n            }\n        }\n\n        vector<uint32_t> cand_masks = generate_candidate_masks(blockers, invw, adjw, P);\n        EvalCand best;\n\n        auto code_of = [&](const vector<int>& ds) -> uint64_t {\n            uint64_t x = 0;\n            for (int d : ds) x = x * 11 + (uint64_t)(d + 1);\n            return x;\n        };\n\n        for (int midx = 0; midx < (int)cand_masks.size(); midx++) {\n            uint32_t mask = cand_masks[midx];\n            auto segs = decode_mask(t, mask);\n\n            unordered_set<uint64_t> seen;\n            seen.reserve(4);\n\n            vector<int> dests;\n            long long assign_cost;\n            if (assign_unique_destinations(st, src, cur, segs, blockers, P, dests, assign_cost)) {\n                uint64_t code = code_of(dests);\n                if (seen.insert(code).second) {\n                    evaluate_assignment(st, cur, src, pos, segs, dests, assign_cost, P, rng, best);\n                }\n            }\n\n            if (P.try_reuse_assignment) {\n                int extra = (midx < P.reuse_expand_masks ? P.reuse_variants : 0);\n                auto plans = greedy_reuse_assignment_variants(st, src, pos, cur, segs, blockers, P, extra);\n                for (auto& pl : plans) {\n                    uint64_t code = code_of(pl.dests);\n                    if (seen.insert(code).second) {\n                        evaluate_assignment(st, cur, src, pos, segs, pl.dests, pl.cost, P, rng, best);\n                    }\n                }\n            }\n        }\n\n        if (best.segs.empty()) {\n            best.segs = {{0, t - 1}};\n            for (int d = 0; d < m; d++) {\n                if (d != src) {\n                    best.dests = {d};\n                    break;\n                }\n            }\n            best.score = 0;\n            best.assign_cost = 0;\n        }\n\n        return best;\n    }\n\n    Result run_one(const Policy& P, XorShift64& rng) const {\n        vector<vector<int>> st = init_st;\n        vector<pair<int,int>> ops;\n        long long energy = 0;\n        int cur = 1;\n\n        remove_possible(st, ops, cur);\n\n        while (cur <= n) {\n            auto [src, pos] = find_box(st, cur);\n            vector<int> blockers(st[src].begin() + pos + 1, st[src].end());\n\n            if (blockers.empty()) {\n                remove_possible(st, ops, cur);\n                continue;\n            }\n\n            EvalCand best = choose_best_action(st, cur, src, pos, blockers, P, rng);\n\n            for (int idx = (int)best.segs.size() - 1; idx >= 0; idx--) {\n                int l = best.segs[idx].first;\n                int start = pos + 1 + l;\n                int dst = best.dests[idx];\n\n                int moved = (int)st[src].size() - start;\n                energy += moved + 1;\n                ops.push_back({st[src][start], dst + 1});\n\n                vector<int> seg(st[src].begin() + start, st[src].end());\n                st[src].erase(st[src].begin() + start, st[src].end());\n                st[dst].insert(st[dst].end(), seg.begin(), seg.end());\n            }\n\n            remove_possible(st, ops, cur);\n        }\n\n        return {energy, ops};\n    }\n\n    vector<Policy> build_bases() const {\n        vector<Policy> ps;\n\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 20; p.boundary_B = 7;\n            p.move_pen = 14; p.seg_inv_w = 3; p.seg_adj_w = 9;\n            p.dest_inv_w = 7; p.fit_w = 3; p.top_w = 2; p.size_w = 1; p.empty_bonus = 20; p.bad_fit_base = 24; p.bad_fit_mul = 3;\n            p.final_move_w = 340; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 28; p.final_future2_w = 6;\n            p.final_empty_shortage_w = 180; p.final_removed_bonus = 420; p.future_depth = 4;\n            p.gen_pen1 = 4; p.gen_pen2 = 7; p.gen_pen3 = 9; p.use_dec_runs = true;\n            p.try_reuse_assignment = true; p.reuse_expand_masks = 2; p.reuse_variants = 1;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 24; p.boundary_B = 7;\n            p.move_pen = 12; p.seg_inv_w = 2; p.seg_adj_w = 8;\n            p.dest_inv_w = 7; p.fit_w = 3; p.top_w = 2; p.size_w = 1; p.empty_bonus = 22; p.bad_fit_base = 24; p.bad_fit_mul = 3;\n            p.final_move_w = 320; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 26; p.final_future2_w = 6;\n            p.final_empty_shortage_w = 170; p.final_removed_bonus = 430; p.future_depth = 4;\n            p.gen_pen1 = 3; p.gen_pen2 = 6; p.gen_pen3 = 8; p.use_dec_runs = true;\n            p.try_reuse_assignment = true; p.reuse_expand_masks = 2; p.reuse_variants = 1;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 18; p.boundary_B = 6;\n            p.move_pen = 16; p.seg_inv_w = 4; p.seg_adj_w = 10;\n            p.dest_inv_w = 8; p.fit_w = 4; p.top_w = 2; p.size_w = 1; p.empty_bonus = 18; p.bad_fit_base = 26; p.bad_fit_mul = 3;\n            p.final_move_w = 360; p.final_assign_w = 1; p.final_global_w = 7; p.final_future_w = 30; p.final_future2_w = 7;\n            p.final_empty_shortage_w = 220; p.final_removed_bonus = 400; p.future_depth = 4;\n            p.gen_pen1 = 5; p.gen_pen2 = 8; p.gen_pen3 = 10; p.use_dec_runs = true;\n            p.try_reuse_assignment = false; p.reuse_expand_masks = 0; p.reuse_variants = 0;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 22; p.boundary_B = 8;\n            p.move_pen = 11; p.seg_inv_w = 2; p.seg_adj_w = 7;\n            p.dest_inv_w = 6; p.fit_w = 2; p.top_w = 1; p.size_w = 1; p.empty_bonus = 24; p.bad_fit_base = 22; p.bad_fit_mul = 2;\n            p.final_move_w = 300; p.final_assign_w = 1; p.final_global_w = 5; p.final_future_w = 24; p.final_future2_w = 5;\n            p.final_empty_shortage_w = 150; p.final_removed_bonus = 470; p.future_depth = 5;\n            p.gen_pen1 = 3; p.gen_pen2 = 5; p.gen_pen3 = 7; p.use_dec_runs = true;\n            p.try_reuse_assignment = true; p.reuse_expand_masks = 3; p.reuse_variants = 1;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 4; p.shortlist = 20; p.boundary_B = 7;\n            p.move_pen = 15; p.seg_inv_w = 3; p.seg_adj_w = 11;\n            p.dest_inv_w = 8; p.fit_w = 3; p.top_w = 3; p.size_w = 1; p.empty_bonus = 18; p.bad_fit_base = 26; p.bad_fit_mul = 4;\n            p.final_move_w = 350; p.final_assign_w = 1; p.final_global_w = 7; p.final_future_w = 32; p.final_future2_w = 8;\n            p.final_empty_shortage_w = 240; p.final_removed_bonus = 390; p.future_depth = 5;\n            p.gen_pen1 = 4; p.gen_pen2 = 7; p.gen_pen3 = 10; p.use_dec_runs = false;\n            p.try_reuse_assignment = false; p.reuse_expand_masks = 0; p.reuse_variants = 0;\n            ps.push_back(p);\n        }\n        {\n            Policy p;\n            p.max_chunks = 5; p.shortlist = 18; p.boundary_B = 8;\n            p.move_pen = 13; p.seg_inv_w = 3; p.seg_adj_w = 8;\n            p.dest_inv_w = 7; p.fit_w = 4; p.top_w = 2; p.size_w = 1; p.empty_bonus = 20; p.bad_fit_base = 23; p.bad_fit_mul = 3;\n            p.final_move_w = 330; p.final_assign_w = 1; p.final_global_w = 6; p.final_future_w = 29; p.final_future2_w = 7;\n            p.final_empty_shortage_w = 200; p.final_removed_bonus = 425; p.future_depth = 5;\n            p.gen_pen1 = 4; p.gen_pen2 = 6; p.gen_pen3 = 9; p.use_dec_runs = true;\n            p.try_reuse_assignment = true; p.reuse_expand_masks = 2; p.reuse_variants = 1;\n            ps.push_back(p);\n        }\n\n        return ps;\n    }\n\n    Policy perturb_policy(const Policy& base, XorShift64& rng, bool around_best) const {\n        Policy p = base;\n        auto perturb = [&](int v, int d, int lo, int hi) {\n            return max(lo, min(hi, v + rng.next_int(-d, d)));\n        };\n\n        int s = around_best ? 1 : 2;\n        int t = around_best ? 2 : 4;\n\n        p.max_chunks             = perturb(p.max_chunks,             1, 3, 5);\n        p.shortlist              = perturb(p.shortlist,              t, 12, 30);\n        p.boundary_B             = perturb(p.boundary_B,             s, 5, 8);\n\n        p.move_pen               = perturb(p.move_pen,               t, 8, 20);\n        p.seg_inv_w              = perturb(p.seg_inv_w,              s, 0, 6);\n        p.seg_adj_w              = perturb(p.seg_adj_w,              t, 4, 14);\n\n        p.dest_inv_w             = perturb(p.dest_inv_w,             s, 4, 10);\n        p.fit_w                  = perturb(p.fit_w,                  s, 1, 5);\n        p.top_w                  = perturb(p.top_w,                  s, 0, 4);\n        p.size_w                 = perturb(p.size_w,                 s, 0, 3);\n        p.empty_bonus            = perturb(p.empty_bonus,            t, 10, 28);\n        p.bad_fit_base           = perturb(p.bad_fit_base,           2 * s + 2, 8, 35);\n        p.bad_fit_mul            = perturb(p.bad_fit_mul,            s, 1, 6);\n\n        p.final_move_w           = perturb(p.final_move_w,           around_best ? 20 : 40, 240, 420);\n        p.final_assign_w         = perturb(p.final_assign_w,         0, 1, 2);\n        p.final_global_w         = perturb(p.final_global_w,         s + 1, 3, 10);\n        p.final_future_w         = perturb(p.final_future_w,         t, 18, 40);\n        p.final_future2_w        = perturb(p.final_future2_w,        s + 1, 2, 12);\n        p.final_empty_shortage_w = perturb(p.final_empty_shortage_w, around_best ? 20 : 35, 80, 320);\n        p.final_removed_bonus    = perturb(p.final_removed_bonus,    around_best ? 30 : 50, 280, 520);\n        p.future_depth           = perturb(p.future_depth,           1, 3, 6);\n\n        p.gen_pen1               = perturb(p.gen_pen1,               s, 1, 8);\n        p.gen_pen2               = perturb(p.gen_pen2,               s, 3, 10);\n        p.gen_pen3               = perturb(p.gen_pen3,               s + 1, 4, 12);\n        if (p.gen_pen1 > p.gen_pen2) swap(p.gen_pen1, p.gen_pen2);\n\n        if ((rng.next() & (around_best ? 15ULL : 7ULL)) == 0) p.use_dec_runs = !p.use_dec_runs;\n        if ((rng.next() & (around_best ? 31ULL : 7ULL)) == 0) p.try_reuse_assignment = !p.try_reuse_assignment;\n\n        p.reuse_expand_masks     = perturb(p.reuse_expand_masks,     1, 1, 4);\n        p.reuse_variants         = perturb(p.reuse_variants,         1, 0, 1);\n\n        return p;\n    }\n\n    Result solve() const {\n        uint64_t seed = 0x123456789abcdef0ULL;\n        for (const auto& s : init_st) for (int x : s) seed = splitmix64(seed ^ (uint64_t)x);\n        XorShift64 rng(seed);\n\n        vector<Policy> bases = build_bases();\n        Result best{(1LL << 60), {}};\n        Policy best_policy = bases[0];\n\n        vector<pair<long long, Policy>> elites;\n\n        auto add_elite = [&](const Policy& p, long long energy) {\n            for (auto& e : elites) {\n                if (same_policy(e.second, p)) {\n                    e.first = min(e.first, energy);\n                    sort(elites.begin(), elites.end(), [](const auto& a, const auto& b) {\n                        return a.first < b.first;\n                    });\n                    return;\n                }\n            }\n            elites.push_back({energy, p});\n            sort(elites.begin(), elites.end(), [](const auto& a, const auto& b) {\n                return a.first < b.first;\n            });\n            const int ELITE_MAX = 8;\n            if ((int)elites.size() > ELITE_MAX) elites.resize(ELITE_MAX);\n        };\n\n        auto pick_elite = [&]() -> Policy {\n            int k = (int)elites.size();\n            int sum = k * (k + 1) / 2;\n            int r = rng.next_int(1, sum);\n            int acc = 0;\n            for (int i = 0; i < k; i++) {\n                acc += (k - i);\n                if (r <= acc) return elites[i].second;\n            }\n            return elites[0].second;\n        };\n\n        auto start_time = chrono::steady_clock::now();\n        auto elapsed_ms = [&]() -> double {\n            auto now = chrono::steady_clock::now();\n            return chrono::duration<double, milli>(now - start_time).count();\n        };\n\n        for (const auto& p : bases) {\n            auto r = run_one(p, rng);\n            add_elite(p, r.energy);\n            if (r.energy < best.energy) {\n                best = move(r);\n                best_policy = p;\n            }\n        }\n\n        const double T_END = 1880.0;\n        const double T_INTENSIFY = 1580.0;\n\n        while (elapsed_ms() < T_END) {\n            double tnow = elapsed_ms();\n            Policy p;\n\n            if (tnow < T_INTENSIFY) {\n                int mode = rng.next_int(0, 99);\n                if (!elites.empty() && mode < 55) {\n                    p = perturb_policy(pick_elite(), rng, true);\n                } else if (mode < 75) {\n                    p = perturb_policy(best_policy, rng, true);\n                } else if (mode < 92) {\n                    p = perturb_policy(bases[rng.next_int(0, (int)bases.size() - 1)], rng, false);\n                } else {\n                    p = (!elites.empty() ? pick_elite() : best_policy);\n                }\n            } else {\n                int mode = rng.next_int(0, 99);\n                if (mode < 45) {\n                    p = best_policy;\n                } else if (mode < 80) {\n                    p = perturb_policy(best_policy, rng, true);\n                } else if (!elites.empty() && mode < 95) {\n                    p = perturb_policy(pick_elite(), rng, true);\n                } else {\n                    p = perturb_policy(best_policy, rng, false);\n                }\n            }\n\n            auto r = run_one(p, rng);\n            add_elite(p, r.energy);\n            if (r.energy < best.energy) {\n                best = move(r);\n                best_policy = p;\n            }\n        }\n\n        return best;\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>> st(m, vector<int>(n / m));\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < n / m; j++) cin >> st[i][j];\n    }\n\n    Simulator sim(n, m, st);\n    Result res = sim.solve();\n\n    for (auto [v, i] : res.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(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() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\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 EvalResult {\n    long double score;\n    vector<long long> contrib;\n    vector<int> cnt_in;\n};\n\nstruct Candidate {\n    vector<int> wps;   // canonicalized or actually-used waypoint list\n    vector<int> seq;   // realized route\n    long double score = 1e100L;\n};\n\nstatic constexpr long double INF_SCORE = 1e100L;\n\nint N, Vn;\nvector<vector<int>> g;\nvector<int> dirt;\nvector<double> potv;\n\nvector<uint16_t> distmat;\nvector<uint16_t> parmat;\n\ninline int VID(int r, int c) { return r * N + c; }\ninline uint16_t& DIST(int s, int t) { return distmat[s * Vn + t]; }\ninline uint16_t& PAR(int s, int t) { return parmat[s * Vn + t]; }\n\nEvalResult evaluate_route(const vector<int>& seq, bool detail = true) {\n    int L = (int)seq.size() - 1;\n    if (L <= 0) return {INF_SCORE, {}, {}};\n\n    vector<int> first(Vn, -1), last(Vn, -1), cnt(Vn, 0);\n    vector<long long> gapsum(Vn, 0);\n\n    for (int t = 1; t <= L; t++) {\n        int v = seq[t];\n        cnt[v]++;\n        if (first[v] == -1) {\n            first[v] = last[v] = t;\n        } else {\n            long long gap = t - last[v];\n            gapsum[v] += gap * (gap - 1) / 2;\n            last[v] = t;\n        }\n    }\n\n    long double total = 0;\n    vector<long long> contrib;\n    if (detail) contrib.assign(Vn, 0);\n\n    for (int v = 0; v < Vn; v++) {\n        if (cnt[v] == 0) return {INF_SCORE, {}, {}};\n        long long gap = first[v] + L - last[v];\n        gapsum[v] += gap * (gap - 1) / 2;\n        long long c = gapsum[v] * 1LL * dirt[v];\n        total += (long double)c;\n        if (detail) contrib[v] = c;\n    }\n\n    EvalResult res;\n    res.score = total / (long double)L;\n    if (detail) {\n        res.contrib = move(contrib);\n        res.cnt_in = move(cnt);\n    }\n    return res;\n}\n\nbool route_visits_all(const vector<int>& seq) {\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    for (int v : seq) seen[v] = 1;\n    for (int i = 0; i < Vn; i++) if (!seen[i]) return false;\n    return true;\n}\n\nvoid reconstruct_path_vertices(int s, int t, vector<int>& out) {\n    out.clear();\n    if (s == t) {\n        out.push_back(s);\n        return;\n    }\n    int cur = t;\n    out.push_back(t);\n    while (cur != s) {\n        cur = PAR(s, cur);\n        out.push_back(cur);\n    }\n    reverse(out.begin(), out.end());\n}\n\nbool append_path_mark(vector<int>& seq, int s, int t, vector<char>& seen, int& seen_cnt) {\n    if (s == t) return true;\n    static vector<int> path;\n    reconstruct_path_vertices(s, t, path);\n    for (int i = 1; i < (int)path.size(); i++) {\n        int v = path[i];\n        seq.push_back(v);\n        if (!seen[v]) {\n            seen[v] = 1;\n            seen_cnt++;\n        }\n        if ((int)seq.size() - 1 > 100000) return false;\n    }\n    return true;\n}\n\nbool build_route_from_waypoints_ex(\n    const vector<int>& wps,\n    vector<int>& seq,\n    const vector<char>* force_visit,\n    vector<int>* used_wps_out = nullptr\n) {\n    seq.clear();\n    seq.push_back(0);\n\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1;\n    int cur = 0;\n    vector<int> used_wps;\n    used_wps.reserve(wps.size());\n\n    for (int x : wps) {\n        bool must_visit = (force_visit != nullptr && (*force_visit)[x]);\n        if (seen[x] && !must_visit) continue;\n        if (!append_path_mark(seq, cur, x, seen, seen_cnt)) return false;\n        used_wps.push_back(x);\n        cur = x;\n    }\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        uint16_t bestd = numeric_limits<uint16_t>::max();\n        double bestpot = -1;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            uint16_t d = DIST(cur, v);\n            if (d < bestd || (d == bestd && potv[v] > bestpot)) {\n                bestd = d;\n                bestpot = potv[v];\n                best = v;\n            }\n        }\n        if (best == -1) break;\n        if (!append_path_mark(seq, cur, best, seen, seen_cnt)) return false;\n        used_wps.push_back(best);\n        cur = best;\n    }\n\n    if (!append_path_mark(seq, cur, 0, seen, seen_cnt)) return false;\n    if (!route_visits_all(seq)) return false;\n\n    if (used_wps_out) *used_wps_out = move(used_wps);\n    return true;\n}\n\nbool build_route_from_waypoints(const vector<int>& wps, vector<int>& seq, vector<int>* used_wps_out = nullptr) {\n    return build_route_from_waypoints_ex(wps, seq, nullptr, used_wps_out);\n}\n\nCandidate make_candidate_from_wps(const vector<int>& wps) {\n    Candidate c;\n    if (!build_route_from_waypoints(wps, c.seq, &c.wps)) {\n        c.score = INF_SCORE;\n        return c;\n    }\n    c.score = evaluate_route(c.seq, false).score;\n    return c;\n}\n\nCandidate make_candidate_from_wps_forced(const vector<int>& raw_wps, const vector<char>& force_visit) {\n    Candidate c;\n    if (!build_route_from_waypoints_ex(raw_wps, c.seq, &force_visit, &c.wps)) {\n        c.score = INF_SCORE;\n        return c;\n    }\n    c.score = evaluate_route(c.seq, false).score;\n    return c;\n}\n\nint waypoint_chain_len(const vector<int>& wps) {\n    if (wps.empty()) return 0;\n    int len = DIST(0, wps[0]);\n    for (int i = 0; i + 1 < (int)wps.size(); i++) len += DIST(wps[i], wps[i + 1]);\n    len += DIST(wps.back(), 0);\n    return len;\n}\n\nvector<int> make_row_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; j++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int j = N - 1; j >= 0; j--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nvector<int> make_col_snake() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int j = 0; j < N; j++) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; i++) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        } else {\n            for (int i = N - 1; i >= 0; i--) {\n                int v = VID(i, j);\n                if (v != 0) ord.push_back(v);\n            }\n        }\n    }\n    return ord;\n}\n\nuint64_t morton_code(int x, int y) {\n    uint64_t z = 0;\n    for (int b = 0; b < 6; b++) {\n        z |= ((uint64_t)((x >> b) & 1)) << (2 * b);\n        z |= ((uint64_t)((y >> b) & 1)) << (2 * b + 1);\n    }\n    return z;\n}\n\nvector<int> make_morton() {\n    vector<pair<uint64_t,int>> arr;\n    arr.reserve(Vn - 1);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        int v = VID(i, j);\n        if (v != 0) arr.push_back({morton_code(i, j), v});\n    }\n    sort(arr.begin(), arr.end());\n    vector<int> ord;\n    ord.reserve(arr.size());\n    for (auto &p : arr) ord.push_back(p.second);\n    return ord;\n}\n\nvector<int> make_pot_desc() {\n    vector<int> ord;\n    ord.reserve(Vn - 1);\n    for (int v = 1; v < Vn; v++) ord.push_back(v);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (potv[a] != potv[b]) return potv[a] > potv[b];\n        return dirt[a] > dirt[b];\n    });\n    return ord;\n}\n\nvector<int> make_bfs_order() {\n    vector<int> ord;\n    vector<char> vis(Vn, 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        if (v != 0) ord.push_back(v);\n        for (int to : g[v]) if (!vis[to]) {\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_dfs_order() {\n    vector<int> ord;\n    vector<char> vis(Vn, 0);\n    vector<int> st = {0};\n    while (!st.empty()) {\n        int v = st.back();\n        st.pop_back();\n        if (vis[v]) continue;\n        vis[v] = 1;\n        if (v != 0) ord.push_back(v);\n        for (int i = (int)g[v].size() - 1; i >= 0; i--) {\n            int to = g[v][i];\n            if (!vis[to]) st.push_back(to);\n        }\n    }\n    return ord;\n}\n\nvector<int> make_greedy_waypoints(double alpha, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double d = (double)DIST(cur, v);\n            double sc = potv[v] / pow(d + 1.0, alpha) + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nvector<int> make_greedy_mix(double lam, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double sc = potv[v] - lam * (double)DIST(cur, v) + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nvector<int> make_density_waypoints(double beta_return, double gamma_end, double noise, RNG& rng) {\n    vector<int> wps;\n    vector<char> seen(Vn, 0);\n    seen[0] = 1;\n    int seen_cnt = 1, cur = 0;\n\n    while (seen_cnt < Vn) {\n        int best = -1;\n        double best_sc = -1e100;\n        for (int v = 0; v < Vn; v++) if (!seen[v]) {\n            double unc = 0.0;\n            int x = v;\n            while (x != cur) {\n                if (!seen[x]) unc += potv[x];\n                x = PAR(cur, x);\n            }\n            double len = DIST(cur, v);\n            double ret = DIST(v, 0);\n            double sc = unc / (len + beta_return * ret + 1.0)\n                      + gamma_end * potv[v] / (len + 1.0)\n                      + noise * rng.next_double();\n            if (sc > best_sc) best_sc = sc, best = v;\n        }\n        if (best == -1) break;\n        wps.push_back(best);\n        static vector<int> path;\n        reconstruct_path_vertices(cur, best, path);\n        for (int x : path) if (!seen[x]) seen[x] = 1, seen_cnt++;\n        cur = best;\n    }\n    return wps;\n}\n\nstring seq_to_moves(const vector<int>& seq) {\n    string ans;\n    ans.reserve(seq.size());\n    for (int i = 1; i < (int)seq.size(); i++) {\n        int a = seq[i - 1], b = seq[i];\n        int ar = a / N, ac = a % N;\n        int br = b / N, bc = b % N;\n        if (br == ar - 1 && bc == ac) ans.push_back('U');\n        else if (br == ar + 1 && bc == ac) ans.push_back('D');\n        else if (br == ar && bc == ac - 1) ans.push_back('L');\n        else if (br == ar && bc == ac + 1) ans.push_back('R');\n        else ans.push_back('?');\n    }\n    return ans;\n}\n\nvector<int> build_segment_anchor_to_x(int anchor, int x) {\n    vector<int> path;\n    reconstruct_path_vertices(anchor, x, path);\n    vector<int> seg;\n    for (int i = 1; i < (int)path.size(); i++) seg.push_back(path[i]);\n    for (int i = (int)path.size() - 2; i >= 0; i--) seg.push_back(path[i]);\n    return seg;\n}\n\nvector<int> build_segment_anchor_x_y(int anchor, int x, int y) {\n    vector<int> p1, p2, p3;\n    reconstruct_path_vertices(anchor, x, p1);\n    reconstruct_path_vertices(x, y, p2);\n    reconstruct_path_vertices(y, anchor, p3);\n\n    vector<int> seg;\n    for (int i = 1; i < (int)p1.size(); i++) seg.push_back(p1[i]);\n    for (int i = 1; i < (int)p2.size(); i++) seg.push_back(p2[i]);\n    for (int i = 1; i < (int)p3.size(); i++) seg.push_back(p3[i]);\n    return seg;\n}\n\nvector<int> apply_segment_periodic(\n    const vector<int>& seq,\n    int anchor,\n    const vector<int>& seg,\n    int step,\n    int offset\n) {\n    int L = (int)seq.size() - 1;\n    vector<int> res;\n    res.reserve(min(100000, L + 1 + 20000));\n    res.push_back(seq[0]);\n\n    int occ = 0;\n    bool inserted = false;\n\n    for (int i = 0; i < L; i++) {\n        int cur = seq[i];\n        if (cur == anchor) {\n            if (occ % step == offset) {\n                for (int x : seg) {\n                    res.push_back(x);\n                    if ((int)res.size() - 1 > 100000) return {};\n                }\n                inserted = true;\n            }\n            occ++;\n        }\n        res.push_back(seq[i + 1]);\n        if ((int)res.size() - 1 > 100000) return {};\n    }\n\n    if (!inserted) return {};\n    return res;\n}\n\nvoid improve_by_guided_delete(Candidate& cur, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n    while (timer.elapsed() < end_time && !cur.wps.empty()) {\n        int m = (int)cur.wps.size();\n        vector<pair<int,int>> deltas;\n        deltas.reserve(m);\n\n        for (int i = 0; i < m; i++) {\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            int c = (i + 1 == m ? 0 : cur.wps[i + 1]);\n            int delta = (int)DIST(a, c) - (int)DIST(a, b) - (int)DIST(b, c);\n            deltas.push_back({delta, i});\n        }\n        sort(deltas.begin(), deltas.end());\n        int K = min(10, (int)deltas.size());\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (int k = 0; k < K && timer.elapsed() < end_time; k++) {\n            int i = deltas[k].second;\n            if (i >= (int)cur.wps.size()) continue;\n            vector<int> nwps = cur.wps;\n            nwps.erase(nwps.begin() + i);\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + EPS < best_sc) {\n                best_sc = cand.score;\n                best_cand = move(cand);\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_hot_insert(Candidate& cur, const vector<int>& hot_vertices, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time) {\n        int m = (int)cur.wps.size();\n        vector<char> in_wps(Vn, 0);\n        for (int x : cur.wps) in_wps[x] = 1;\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        int HOT = min((int)hot_vertices.size(), 18);\n\n        for (int hi = 0; hi < HOT && timer.elapsed() < end_time; hi++) {\n            int x = hot_vertices[hi];\n            if (in_wps[x]) continue;\n\n            vector<pair<int,int>> pos_delta;\n            pos_delta.reserve(m + 1);\n\n            for (int pos = 0; pos <= m; pos++) {\n                int prev = (pos == 0 ? 0 : cur.wps[pos - 1]);\n                int next = (pos == m ? 0 : cur.wps[pos]);\n                int delta = (int)DIST(prev, x) + (int)DIST(x, next) - (int)DIST(prev, next);\n                pos_delta.push_back({delta, pos});\n            }\n\n            sort(pos_delta.begin(), pos_delta.end());\n            int K = min(4, (int)pos_delta.size());\n\n            for (int kk = 0; kk < K && timer.elapsed() < end_time; kk++) {\n                int pos = pos_delta[kk].second;\n                vector<int> nwps = cur.wps;\n                nwps.insert(nwps.begin() + pos, x);\n                Candidate cand = make_candidate_from_wps(nwps);\n                if (cand.score + EPS < best_sc) {\n                    best_sc = cand.score;\n                    best_cand = move(cand);\n                    found = true;\n                }\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_exact_hot_replace(Candidate& cur, const vector<int>& hot_vertices, Timer& timer, double end_time) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time && !cur.wps.empty()) {\n        int m = (int)cur.wps.size();\n        vector<char> in_wps(Vn, 0);\n        for (int x : cur.wps) in_wps[x] = 1;\n\n        vector<int> weak_pos(m);\n        iota(weak_pos.begin(), weak_pos.end(), 0);\n        sort(weak_pos.begin(), weak_pos.end(), [&](int i, int j) {\n            if (potv[cur.wps[i]] != potv[cur.wps[j]]) return potv[cur.wps[i]] < potv[cur.wps[j]];\n            return dirt[cur.wps[i]] < dirt[cur.wps[j]];\n        });\n        if ((int)weak_pos.size() > 10) weak_pos.resize(10);\n\n        vector<int> hot_free;\n        for (int x : hot_vertices) {\n            if (!in_wps[x]) hot_free.push_back(x);\n            if ((int)hot_free.size() >= 18) break;\n        }\n        if (hot_free.empty()) break;\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (int x : hot_free) {\n            if (timer.elapsed() >= end_time) break;\n\n            vector<pair<int,int>> ranked;\n            for (int pos : weak_pos) {\n                int oldv = cur.wps[pos];\n                int prev = (pos == 0 ? 0 : cur.wps[pos - 1]);\n                int next = (pos + 1 == m ? 0 : cur.wps[pos + 1]);\n                int oldc = (int)DIST(prev, oldv) + (int)DIST(oldv, next);\n                int newc = (int)DIST(prev, x) + (int)DIST(x, next);\n                ranked.push_back({newc - oldc, pos});\n            }\n            sort(ranked.begin(), ranked.end());\n            int K = min(4, (int)ranked.size());\n\n            for (int k = 0; k < K && timer.elapsed() < end_time; k++) {\n                int pos = ranked[k].second;\n                vector<int> nwps = cur.wps;\n                nwps[pos] = x;\n                Candidate cand = make_candidate_from_wps(nwps);\n                if (cand.score + EPS < best_sc) {\n                    best_sc = cand.score;\n                    best_cand = move(cand);\n                    found = true;\n                }\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nvoid improve_by_exact_two_opt_local(Candidate& cur, Timer& timer, double end_time, RNG& rng) {\n    const long double EPS = 1e-12L;\n\n    while (timer.elapsed() < end_time) {\n        int m = (int)cur.wps.size();\n        if (m < 2) break;\n\n        vector<tuple<int,int,int>> cand_moves;\n\n        for (int i = 0; i < m; i++) {\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            for (int len = 1; len <= 10 && i + len < m; len++) {\n                int j = i + len;\n                int c = cur.wps[j];\n                int d = (j + 1 == m ? 0 : cur.wps[j + 1]);\n                int delta = (int)DIST(a, c) + (int)DIST(b, d)\n                          - (int)DIST(a, b) - (int)DIST(c, d);\n                cand_moves.push_back({delta, i, j});\n            }\n        }\n\n        for (int t = 0; t < 100; t++) {\n            int i = rng.next_int(m);\n            int j = rng.next_int(m);\n            if (i > j) swap(i, j);\n            if (i == j) continue;\n            int a = (i == 0 ? 0 : cur.wps[i - 1]);\n            int b = cur.wps[i];\n            int c = cur.wps[j];\n            int d = (j + 1 == m ? 0 : cur.wps[j + 1]);\n            int delta = (int)DIST(a, c) + (int)DIST(b, d)\n                      - (int)DIST(a, b) - (int)DIST(c, d);\n            cand_moves.push_back({delta, i, j});\n        }\n\n        sort(cand_moves.begin(), cand_moves.end());\n        if ((int)cand_moves.size() > 12) cand_moves.resize(12);\n\n        long double best_sc = cur.score;\n        Candidate best_cand;\n        bool found = false;\n\n        for (auto [delta, i, j] : cand_moves) {\n            if (timer.elapsed() >= end_time) break;\n            vector<int> nwps = cur.wps;\n            reverse(nwps.begin() + i, nwps.begin() + j + 1);\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + EPS < best_sc) {\n                best_sc = cand.score;\n                best_cand = move(cand);\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        cur = move(best_cand);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    Vn = N * N;\n\n    vector<string> h(N - 1), vstr(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vstr[i];\n\n    dirt.assign(Vn, 0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        cin >> dirt[VID(i, j)];\n    }\n\n    g.assign(Vn, {});\n    for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) {\n        if (h[i][j] == '0') {\n            int a = VID(i, j), b = VID(i + 1, j);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n    for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) {\n        if (vstr[i][j] == '0') {\n            int a = VID(i, j), b = VID(i, j + 1);\n            g[a].push_back(b);\n            g[b].push_back(a);\n        }\n    }\n\n    potv.assign(Vn, 0.0);\n    for (int s = 0; s < Vn; s++) {\n        potv[s] += dirt[s];\n        vector<int> dist(Vn, -1);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int x = q.front(); q.pop();\n            if (dist[x] == 3) continue;\n            for (int to : g[x]) {\n                if (dist[to] != -1) continue;\n                dist[to] = dist[x] + 1;\n                q.push(to);\n                if (dist[to] == 1) potv[s] += 0.50 * dirt[to];\n                else if (dist[to] == 2) potv[s] += 0.20 * dirt[to];\n                else if (dist[to] == 3) potv[s] += 0.08 * dirt[to];\n            }\n        }\n    }\n\n    for (int v = 0; v < Vn; v++) {\n        sort(g[v].begin(), g[v].end(), [&](int a, int b) {\n            if (potv[a] != potv[b]) return potv[a] > potv[b];\n            return dirt[a] > dirt[b];\n        });\n    }\n\n    vector<int> hot_vertices;\n    for (int v = 1; v < Vn; v++) hot_vertices.push_back(v);\n    sort(hot_vertices.begin(), hot_vertices.end(), [&](int a, int b) {\n        if (potv[a] != potv[b]) return potv[a] > potv[b];\n        return dirt[a] > dirt[b];\n    });\n\n    vector<char> force8(Vn, 0), force16(Vn, 0);\n    for (int i = 0; i < min(8, (int)hot_vertices.size()); i++) force8[hot_vertices[i]] = 1;\n    for (int i = 0; i < min(16, (int)hot_vertices.size()); i++) force16[hot_vertices[i]] = 1;\n\n    if ((int)hot_vertices.size() > 120) hot_vertices.resize(120);\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    distmat.assign((size_t)Vn * Vn, 0);\n    parmat.assign((size_t)Vn * Vn, 0);\n\n    vector<int> q(Vn);\n    vector<double> bestval(Vn);\n\n    for (int s = 0; s < Vn; s++) {\n        vector<int> order;\n        order.reserve(Vn);\n\n        for (int i = 0; i < Vn; i++) DIST(s, i) = numeric_limits<uint16_t>::max();\n\n        int qh = 0, qt = 0;\n        q[qt++] = s;\n        DIST(s, s) = 0;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            order.push_back(v);\n            uint16_t dv = DIST(s, v);\n            for (int to : g[v]) {\n                if (DIST(s, to) == numeric_limits<uint16_t>::max()) {\n                    DIST(s, to) = dv + 1;\n                    q[qt++] = to;\n                }\n            }\n        }\n\n        for (int i = 0; i < Vn; i++) {\n            bestval[i] = -1e100;\n            PAR(s, i) = (uint16_t)i;\n        }\n        bestval[s] = potv[s];\n        PAR(s, s) = (uint16_t)s;\n\n        for (int v : order) {\n            for (int to : g[v]) {\n                if (DIST(s, to) == DIST(s, v) + 1) {\n                    double nv = bestval[v] + potv[to];\n                    if (nv > bestval[to] + 1e-12) {\n                        bestval[to] = nv;\n                        PAR(s, to) = (uint16_t)v;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Candidate> cands;\n    vector<Candidate> locked_cands; // forced-hot routes, compared later but not locally edited\n\n    auto add_candidate = [&](const vector<int>& wps) {\n        Candidate c = make_candidate_from_wps(wps);\n        if (c.score < INF_SCORE) cands.push_back(move(c));\n    };\n    auto add_locked_forced = [&](const vector<int>& raw_wps, const vector<char>& forcev) {\n        Candidate c = make_candidate_from_wps_forced(raw_wps, forcev);\n        if (c.score < INF_SCORE) locked_cands.push_back(move(c));\n    };\n\n    vector<int> row_snake = make_row_snake();\n    vector<int> col_snake = make_col_snake();\n    vector<int> morton = make_morton();\n    vector<int> pot_desc = make_pot_desc();\n    vector<int> bfs_order = make_bfs_order();\n    vector<int> dfs_order = make_dfs_order();\n    vector<int> greedy12 = make_greedy_waypoints(1.2, 0.0, rng);\n    vector<int> greedy09 = make_greedy_waypoints(0.9, 0.0, rng);\n    vector<int> greedy16 = make_greedy_waypoints(1.6, 0.0, rng);\n    vector<int> greedy12n = make_greedy_waypoints(1.2, 30.0, rng);\n    vector<int> mix8 = make_greedy_mix(8.0, 20.0, rng);\n    vector<int> mix14 = make_greedy_mix(14.0, 30.0, rng);\n    vector<int> dens0 = make_density_waypoints(0.0, 0.05, 0.0, rng);\n    vector<int> dens2 = make_density_waypoints(0.2, 0.05, 0.0, rng);\n    vector<int> dens5 = make_density_waypoints(0.5, 0.08, 10.0, rng);\n\n    add_candidate(row_snake);\n    add_candidate(col_snake);\n    add_candidate(morton);\n    add_candidate(pot_desc);\n    add_candidate(bfs_order);\n    add_candidate(dfs_order);\n    add_candidate(greedy09);\n    add_candidate(greedy12);\n    add_candidate(greedy16);\n    add_candidate(greedy12n);\n    add_candidate(mix8);\n    add_candidate(mix14);\n    add_candidate(dens0);\n    add_candidate(dens2);\n    add_candidate(dens5);\n\n    // forced-hot variants on selected raw lists\n    add_locked_forced(pot_desc, force8);\n    add_locked_forced(pot_desc, force16);\n    add_locked_forced(greedy12, force8);\n    add_locked_forced(greedy12, force16);\n    add_locked_forced(mix8, force8);\n    add_locked_forced(dens0, force8);\n    add_locked_forced(dens2, force8);\n    add_locked_forced(dens2, force16);\n    add_locked_forced(dens5, force8);\n    add_locked_forced(dens5, force16);\n\n    while (timer.elapsed() < 0.46) {\n        int t = rng.next_int(3);\n        vector<int> raw;\n        if (t == 0) {\n            double alpha = 0.8 + 1.4 * rng.next_double();\n            double noise = 10.0 + 60.0 * rng.next_double();\n            raw = make_greedy_waypoints(alpha, noise, rng);\n            add_candidate(raw);\n            if (rng.next_int(2) == 0) add_locked_forced(raw, force8);\n        } else if (t == 1) {\n            double lam = 6.0 + 16.0 * rng.next_double();\n            double noise = 10.0 + 50.0 * rng.next_double();\n            raw = make_greedy_mix(lam, noise, rng);\n            add_candidate(raw);\n            if (rng.next_int(2) == 0) add_locked_forced(raw, force8);\n        } else {\n            double beta = 0.0 + 0.9 * rng.next_double();\n            double gamma = 0.02 + 0.10 * rng.next_double();\n            double noise = 0.0 + 20.0 * rng.next_double();\n            raw = make_density_waypoints(beta, gamma, noise, rng);\n            add_candidate(raw);\n            if (rng.next_int(2) == 0) add_locked_forced(raw, force8);\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n        if (a.score != b.score) return a.score < b.score;\n        return waypoint_chain_len(a.wps) < waypoint_chain_len(b.wps);\n    });\n    if (cands.empty()) {\n        auto c = make_candidate_from_wps(row_snake);\n        cout << seq_to_moves(c.seq) << '\\n';\n        return 0;\n    }\n    if ((int)cands.size() > 6) cands.resize(6);\n\n    Candidate best = cands[0];\n\n    {\n        Candidate cur = best;\n\n        improve_by_guided_delete(cur, timer, 0.95);\n        improve_by_hot_insert(cur, hot_vertices, timer, 1.12);\n        improve_by_exact_hot_replace(cur, hot_vertices, timer, 1.28);\n        improve_by_exact_two_opt_local(cur, timer, 1.42, rng);\n\n        while (timer.elapsed() < 1.64 && !cur.wps.empty()) {\n            vector<int> nwps = cur.wps;\n            int m = (int)nwps.size();\n            int op = rng.next_int(6);\n\n            if (op == 0 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i > j) swap(i, j);\n                if (i == j) continue;\n                reverse(nwps.begin() + i, nwps.begin() + j + 1);\n            } else if (op == 1 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i == j) continue;\n                swap(nwps[i], nwps[j]);\n            } else if (op == 2 && m >= 1) {\n                int i = rng.next_int(m);\n                nwps.erase(nwps.begin() + i);\n            } else if (op == 3 && m >= 1) {\n                int pos = rng.next_int(m + 1);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool ex = false;\n                for (int y : nwps) if (y == x) { ex = true; break; }\n                if (ex) continue;\n                nwps.insert(nwps.begin() + pos, x);\n            } else if (op == 4 && m >= 2) {\n                int i = rng.next_int(m), j = rng.next_int(m);\n                if (i == j) continue;\n                int v = nwps[i];\n                nwps.erase(nwps.begin() + i);\n                if (j > i) j--;\n                nwps.insert(nwps.begin() + j, v);\n            } else if (op == 5 && m >= 1) {\n                int i = rng.next_int(m);\n                int x = hot_vertices[rng.next_int((int)hot_vertices.size())];\n                bool ex = false;\n                for (int y : nwps) if (y == x) { ex = true; break; }\n                if (ex) continue;\n                nwps[i] = x;\n            } else {\n                continue;\n            }\n\n            Candidate cand = make_candidate_from_wps(nwps);\n            if (cand.score + 1e-12L < cur.score) cur = move(cand);\n        }\n\n        improve_by_guided_delete(cur, timer, 1.74);\n        improve_by_exact_hot_replace(cur, hot_vertices, timer, 1.82);\n\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    for (int idx = 1; idx < (int)cands.size() && timer.elapsed() < 1.84; idx++) {\n        Candidate cur = cands[idx];\n        improve_by_guided_delete(cur, timer, 1.88);\n        if (cur.score < best.score) best = move(cur);\n    }\n\n    // compare against locked forced-hot candidates\n    for (auto &c : locked_cands) {\n        if (c.score < best.score) best = c;\n    }\n\n    vector<int> cur_seq = best.seq;\n    EvalResult cur_ev = evaluate_route(cur_seq, true);\n\n    const vector<pair<int,int>> patterns = {\n        {1,0},\n        {2,0},{2,1},\n        {3,0},{3,1},{3,2},\n        {4,0},{4,1},{4,2},{4,3},\n        {5,0},{5,1},{5,2},{5,3},{5,4}\n    };\n\n    for (int round = 0; round < 10 && timer.elapsed() < 1.93; round++) {\n        int L = (int)cur_seq.size() - 1;\n        if (L > 98000) break;\n\n        vector<int> rankv(Vn);\n        iota(rankv.begin(), rankv.end(), 0);\n        sort(rankv.begin(), rankv.end(), [&](int a, int b) {\n            return cur_ev.contrib[a] > cur_ev.contrib[b];\n        });\n\n        vector<int> occ_pos_cnt(Vn, 0);\n        for (int i = 0; i < L; i++) occ_pos_cnt[cur_seq[i]]++;\n\n        long double best_sc = cur_ev.score;\n        vector<int> best_seq2;\n\n        int TOPX = min(Vn, 16);\n        for (int ii = 0; ii < TOPX && timer.elapsed() < 1.92; ii++) {\n            int x = rankv[ii];\n\n            vector<pair<double,int>> anchors;\n            for (int a = 0; a < Vn; a++) {\n                if (a == x || occ_pos_cnt[a] == 0) continue;\n                int d = DIST(a, x);\n                if (d == 0) continue;\n                if (d > 12 && occ_pos_cnt[a] <= 1) continue;\n                double sc = (double)occ_pos_cnt[a] / (double)(d + 1) + 0.001 * potv[a];\n                anchors.push_back({-sc, a});\n            }\n            sort(anchors.begin(), anchors.end());\n            if ((int)anchors.size() > 6) anchors.resize(6);\n\n            for (auto &pa : anchors) {\n                int a = pa.second;\n                vector<int> seg = build_segment_anchor_to_x(a, x);\n                if (seg.empty()) continue;\n                for (auto [step, off] : patterns) {\n                    auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                    if (cand_seq.empty()) continue;\n                    auto ev = evaluate_route(cand_seq, false);\n                    if (ev.score + 1e-12L < best_sc) {\n                        best_sc = ev.score;\n                        best_seq2 = move(cand_seq);\n                    }\n                }\n            }\n\n            vector<int> ycand;\n            for (int jj = 0; jj < min(Vn, 40) && (int)ycand.size() < 4; jj++) {\n                int y = rankv[jj];\n                if (y == x) continue;\n                if (DIST(x, y) <= 6) ycand.push_back(y);\n            }\n\n            for (int y : ycand) {\n                for (auto &pa : anchors) {\n                    int a = pa.second;\n                    int cyc_len = DIST(a, x) + DIST(x, y) + DIST(y, a);\n                    if (cyc_len > 20) continue;\n                    vector<int> seg = build_segment_anchor_x_y(a, x, y);\n                    if (seg.empty()) continue;\n                    for (auto [step, off] : patterns) {\n                        auto cand_seq = apply_segment_periodic(cur_seq, a, seg, step, off);\n                        if (cand_seq.empty()) continue;\n                        auto ev = evaluate_route(cand_seq, false);\n                        if (ev.score + 1e-12L < best_sc) {\n                            best_sc = ev.score;\n                            best_seq2 = move(cand_seq);\n                        }\n                    }\n                }\n            }\n        }\n\n        if (best_seq2.empty()) break;\n        cur_seq = move(best_seq2);\n        cur_ev = evaluate_route(cur_seq, true);\n    }\n\n    cout << seq_to_moves(cur_seq) << '\\n';\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int INF = 1e9;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    void reset() { st = chrono::steady_clock::now(); }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    int N, M;\n    int si, sj;\n    vector<string> board;\n    vector<string> words;\n\n    vector<pair<int,int>> posByChar[26];\n\n    vector<vector<int>> ov;\n    vector<int> startApprox;\n    vector<vector<int>> edgeApprox;\n    vector<int> startLen;\n    vector<vector<int>> edgeLen;\n\n    int charStart[26];\n    int charTrans[26][26];\n\n    static constexpr int POW26_4 = 26 * 26 * 26 * 26;\n    static constexpr int POW26_5 = POW26_4 * 26;\n    vector<int16_t> id5;\n\n    vector<pair<int,int>> pairsApprox;\n    vector<pair<int,int>> pairsLen;\n    vector<pair<int,int>> pairsMix1;\n    vector<pair<int,int>> pairsMix2;\n\n    Timer timer;\n    const double TL = 1.90;\n\n    inline int dist(const pair<int,int>& a, const pair<int,int>& b) const {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    uint64_t hash_order(const vector<int>& ord) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : ord) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    int overlap5(const string& a, const string& b) {\n        for (int k = 4; k >= 0; --k) {\n            bool ok = true;\n            for (int t = 0; t < k; ++t) {\n                if (a[5 - k + t] != b[t]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    int encode5(const string& s) const {\n        int x = 0;\n        for (int i = 0; i < 5; ++i) x = x * 26 + (s[i] - 'A');\n        return x;\n    }\n\n    int cost_from_prev_char(int prevChar, const string& s) {\n        if (s.empty()) return 0;\n        const auto& initList = posByChar[prevChar];\n        vector<int> dp(initList.size(), 0), ndp;\n        const vector<pair<int,int>>* prevList = &initList;\n\n        for (char ch : s) {\n            int c = ch - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    int cost_from_start(const string& s) {\n        if (s.empty()) return 0;\n        int c0 = s[0] - 'A';\n        const auto& firstList = posByChar[c0];\n        vector<int> dp(firstList.size()), ndp;\n        for (int i = 0; i < (int)firstList.size(); ++i) {\n            dp[i] = abs(si - firstList[i].first) + abs(sj - firstList[i].second) + 1;\n        }\n        const vector<pair<int,int>>* prevList = &firstList;\n\n        for (int p = 1; p < (int)s.size(); ++p) {\n            int c = s[p] - 'A';\n            const auto& curList = posByChar[c];\n            ndp.assign((int)curList.size(), INF);\n            for (int j = 0; j < (int)curList.size(); ++j) {\n                int best = INF;\n                for (int i = 0; i < (int)prevList->size(); ++i) {\n                    best = min(best, dp[i] + dist((*prevList)[i], curList[j]) + 1);\n                }\n                ndp[j] = best;\n            }\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n        return *min_element(dp.begin(), dp.end());\n    }\n\n    vector<pair<int,int>> build_pairs(const vector<int>& startC, const vector<vector<int>>& edgeC) {\n        vector<tuple<int,int,int>> tmp;\n        tmp.reserve(M * (M - 1));\n        for (int a = 0; a < M; ++a) {\n            for (int b = 0; b < M; ++b) if (a != b) {\n                tmp.emplace_back(startC[a] + edgeC[a][b], a, b);\n            }\n        }\n        sort(tmp.begin(), tmp.end());\n        vector<pair<int,int>> res;\n        res.reserve(tmp.size());\n        for (auto &[c, a, b] : tmp) {\n            (void)c;\n            res.emplace_back(a, b);\n        }\n        return res;\n    }\n\n    void preprocess() {\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                posByChar[board[i][j] - 'A'].push_back({i, j});\n            }\n        }\n\n        for (int c = 0; c < 26; ++c) {\n            charStart[c] = INF;\n            for (auto &p : posByChar[c]) {\n                charStart[c] = min(charStart[c], abs(si - p.first) + abs(sj - p.second) + 1);\n            }\n        }\n        for (int a = 0; a < 26; ++a) {\n            for (int b = 0; b < 26; ++b) {\n                int best = INF;\n                for (auto &pa : posByChar[a]) for (auto &pb : posByChar[b]) {\n                    best = min(best, dist(pa, pb) + 1);\n                }\n                charTrans[a][b] = best;\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                ov[i][j] = overlap5(words[i], words[j]);\n            }\n        }\n\n        startApprox.assign(M, 0);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        startLen.assign(M, 5);\n        edgeLen.assign(M, vector<int>(M, 5));\n\n        for (int i = 0; i < M; ++i) {\n            startApprox[i] = cost_from_start(words[i]);\n        }\n\n        for (int i = 0; i < M; ++i) {\n            for (int j = 0; j < M; ++j) if (i != j) {\n                int r = ov[i][j];\n                string chunk = words[j].substr(r);\n                edgeApprox[i][j] = cost_from_prev_char(words[i][4] - 'A', chunk);\n                edgeLen[i][j] = 5 - r;\n            }\n        }\n\n        id5.assign(POW26_5, (int16_t)-1);\n        for (int i = 0; i < M; ++i) {\n            id5[encode5(words[i])] = (int16_t)i;\n        }\n\n        vector<int> startMix1(M), startMix2(M);\n        vector<vector<int>> edgeMix1(M, vector<int>(M, 0));\n        vector<vector<int>> edgeMix2(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            startMix1[i] = startApprox[i] + startLen[i];\n            startMix2[i] = startApprox[i] + 2 * startLen[i];\n            for (int j = 0; j < M; ++j) {\n                edgeMix1[i][j] = edgeApprox[i][j] + edgeLen[i][j];\n                edgeMix2[i][j] = edgeApprox[i][j] + 2 * edgeLen[i][j];\n            }\n        }\n\n        pairsApprox = build_pairs(startApprox, edgeApprox);\n        pairsLen    = build_pairs(startLen, edgeLen);\n        pairsMix1   = build_pairs(startMix1, edgeMix1);\n        pairsMix2   = build_pairs(startMix2, edgeMix2);\n    }\n\n    int insertion_delta(\n        const vector<int>& path,\n        int x, int pos,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int m = (int)path.size();\n        if (m == 0) return startC[x];\n        if (pos == 0) {\n            return startC[x] + edgeC[x][path[0]] - startC[path[0]];\n        } else if (pos == m) {\n            return edgeC[path[m - 1]][x];\n        } else {\n            return edgeC[path[pos - 1]][x] + edgeC[x][path[pos]] - edgeC[path[pos - 1]][path[pos]];\n        }\n    }\n\n    vector<int> build_order_cheapest_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        path.push_back(a);\n        used[a] = 1;\n        if (b != -1) {\n            path.push_back(b);\n            used[b] = 1;\n        }\n\n        while ((int)path.size() < M) {\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n        return path;\n    }\n\n    vector<int> build_order_regret_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        path.push_back(a);\n        used[a] = 1;\n        if (b != -1) {\n            path.push_back(b);\n            used[b] = 1;\n        }\n\n        while ((int)path.size() < M) {\n            long long bestMetric = (1LL << 60);\n            int bestDelta = INF;\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                int d1 = INF, d2 = INF, p1 = -1;\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    if (d < d1) {\n                        d2 = d1;\n                        d1 = d;\n                        p1 = pos;\n                    } else if (d < d2) {\n                        d2 = d;\n                    }\n                }\n                if (d2 == INF) d2 = d1;\n                long long metric = 3LL * d1 - d2;\n                if (metric < bestMetric || (metric == bestMetric && d1 < bestDelta)) {\n                    bestMetric = metric;\n                    bestDelta = d1;\n                    bestX = x;\n                    bestPos = p1;\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = 1;\n        }\n\n        return path;\n    }\n\n    vector<int> build_order_randomized_insertion(\n        int a, int b,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int topK,\n        mt19937& rng\n    ) {\n        struct Cand {\n            int delta, x, pos;\n        };\n\n        vector<int> path;\n        vector<char> used(M, 0);\n\n        path.push_back(a);\n        used[a] = 1;\n        if (b != -1) {\n            path.push_back(b);\n            used[b] = 1;\n        }\n\n        while ((int)path.size() < M) {\n            vector<Cand> best(topK, {INF, -1, -1});\n\n            auto push_cand = [&](int delta, int x, int pos) {\n                Cand cur{delta, x, pos};\n                for (int t = 0; t < topK; ++t) {\n                    if (cur.delta < best[t].delta) swap(cur, best[t]);\n                }\n            };\n\n            for (int x = 0; x < M; ++x) if (!used[x]) {\n                for (int pos = 0; pos <= (int)path.size(); ++pos) {\n                    int d = insertion_delta(path, x, pos, startC, edgeC);\n                    push_cand(d, x, pos);\n                }\n            }\n\n            int cnt = 0;\n            while (cnt < topK && best[cnt].x != -1) ++cnt;\n\n            int pick = 0;\n            if (cnt >= 2) {\n                uint32_t r = rng() % 100;\n                if (cnt == 2) {\n                    pick = (r < 78 ? 0 : 1);\n                } else if (cnt == 3) {\n                    if (r < 70) pick = 0;\n                    else if (r < 92) pick = 1;\n                    else pick = 2;\n                } else {\n                    if (r < 62) pick = 0;\n                    else if (r < 84) pick = 1;\n                    else if (r < 95) pick = 2;\n                    else pick = 3;\n                }\n            }\n\n            path.insert(path.begin() + best[pick].pos, best[pick].x);\n            used[best[pick].x] = 1;\n        }\n\n        return path;\n    }\n\n    vector<int> best_rotation(\n        const vector<int>& path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int n = (int)path.size();\n        if (n <= 1) return path;\n\n        int cyc = 0;\n        for (int i = 0; i < n; ++i) {\n            cyc += edgeC[path[i]][path[(i + 1) % n]];\n        }\n\n        int bestBreak = 0;\n        int bestVal = INF;\n        for (int b = 0; b < n; ++b) {\n            int prev = path[(b - 1 + n) % n];\n            int cur = path[b];\n            int val = cyc - edgeC[prev][cur] + startC[cur];\n            if (val < bestVal) {\n                bestVal = val;\n                bestBreak = b;\n            }\n        }\n\n        vector<int> res(n);\n        for (int i = 0; i < n; ++i) res[i] = path[(bestBreak + i) % n];\n        return res;\n    }\n\n    vector<int> improve_relocate(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int maxIter = 200\n    ) {\n        int n = (int)path.size();\n        for (int iter = 0; iter < maxIter; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (int i = 0; i < n; ++i) {\n                int x = path[i];\n\n                int remDelta;\n                if (i == 0) {\n                    int b = path[1];\n                    remDelta = startC[b] - startC[x] - edgeC[x][b];\n                } else if (i == n - 1) {\n                    int a = path[n - 2];\n                    remDelta = -edgeC[a][x];\n                } else {\n                    int a = path[i - 1];\n                    int b = path[i + 1];\n                    remDelta = edgeC[a][b] - edgeC[a][x] - edgeC[x][b];\n                }\n\n                for (int j = 0; j <= n - 1; ++j) {\n                    if (j == i) continue;\n\n                    int left = -1, right = -1;\n                    if (j < i) {\n                        left = (j == 0 ? -1 : path[j - 1]);\n                        right = path[j];\n                    } else {\n                        left = path[j];\n                        right = (j == n - 1 ? -1 : path[j + 1]);\n                    }\n\n                    int insDelta;\n                    if (left == -1) {\n                        insDelta = startC[x] + edgeC[x][right] - startC[right];\n                    } else if (right == -1) {\n                        insDelta = edgeC[left][x];\n                    } else {\n                        insDelta = edgeC[left][x] + edgeC[x][right] - edgeC[left][right];\n                    }\n\n                    int delta = remDelta + insDelta;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            int x = path[bestI];\n            path.erase(path.begin() + bestI);\n            path.insert(path.begin() + bestJ, x);\n\n            if (timer.elapsed() > TL) break;\n        }\n        return path;\n    }\n\n    int adjacent_swap_delta(\n        const vector<int>& path,\n        int i,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC\n    ) {\n        int n = (int)path.size();\n        int a = path[i], b = path[i + 1];\n\n        if (n == 2 && i == 0) {\n            int oldCost = startC[a] + edgeC[a][b];\n            int newCost = startC[b] + edgeC[b][a];\n            return newCost - oldCost;\n        }\n\n        if (i == 0) {\n            int c = path[2];\n            int oldCost = startC[a] + edgeC[a][b] + edgeC[b][c];\n            int newCost = startC[b] + edgeC[b][a] + edgeC[a][c];\n            return newCost - oldCost;\n        }\n\n        if (i + 1 == n - 1) {\n            int p = path[i - 1];\n            int oldCost = edgeC[p][a] + edgeC[a][b];\n            int newCost = edgeC[p][b] + edgeC[b][a];\n            return newCost - oldCost;\n        }\n\n        int p = path[i - 1];\n        int c = path[i + 2];\n        int oldCost = edgeC[p][a] + edgeC[a][b] + edgeC[b][c];\n        int newCost = edgeC[p][b] + edgeC[b][a] + edgeC[a][c];\n        return newCost - oldCost;\n    }\n\n    vector<int> improve_adjacent_swap(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int maxIter = 60\n    ) {\n        int n = (int)path.size();\n        if (n <= 1) return path;\n\n        for (int iter = 0; iter < maxIter; ++iter) {\n            int bestDelta = 0;\n            int bestI = -1;\n            for (int i = 0; i + 1 < n; ++i) {\n                int d = adjacent_swap_delta(path, i, startC, edgeC);\n                if (d < bestDelta) {\n                    bestDelta = d;\n                    bestI = i;\n                }\n            }\n            if (bestDelta >= 0) break;\n            swap(path[bestI], path[bestI + 1]);\n            if (timer.elapsed() > TL) break;\n        }\n        return path;\n    }\n\n    vector<int> polish_order(\n        vector<int> path,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int relocIter,\n        int adjIter\n    ) {\n        path = improve_relocate(move(path), startC, edgeC, relocIter);\n        path = improve_adjacent_swap(move(path), startC, edgeC, adjIter);\n        path = best_rotation(path, startC, edgeC);\n        return path;\n    }\n\n    string build_string(const vector<int>& order) {\n        string s = words[order[0]];\n        s.reserve(5 + 4 * M);\n        for (int k = 1; k < M; ++k) {\n            int i = order[k - 1];\n            int j = order[k];\n            int r = ov[i][j];\n            s += words[j].substr(r);\n        }\n        return s;\n    }\n\n    struct WindowCand {\n        int l, r, len, approx;\n        bool operator<(const WindowCand& other) const {\n            if (len != other.len) return len < other.len;\n            if (approx != other.approx) return approx < other.approx;\n            if (l != other.l) return l < other.l;\n            return r < other.r;\n        }\n    };\n\n    vector<WindowCand> covering_window_candidates(const string& s, int keepK = 3) {\n        int L = (int)s.size();\n        if (L < 5) return {{0, L - 1, L, 0}};\n\n        int T = L - 4;\n        vector<int> ids(T, -1);\n\n        int code = 0;\n        for (int i = 0; i < 5; ++i) code = code * 26 + (s[i] - 'A');\n        ids[0] = id5[code];\n        for (int p = 1; p < T; ++p) {\n            code = (code % POW26_4) * 26 + (s[p + 4] - 'A');\n            ids[p] = id5[code];\n        }\n\n        vector<int> pairPref(L, 0);\n        for (int i = 1; i < L; ++i) {\n            pairPref[i] = pairPref[i - 1] + charTrans[s[i - 1] - 'A'][s[i] - 'A'];\n        }\n\n        auto approxCostSub = [&](int l, int r) -> int {\n            int res = charStart[s[l] - 'A'];\n            res += pairPref[r] - pairPref[l];\n            return res;\n        };\n\n        vector<int> cnt(M, 0);\n        int covered = 0;\n        int l = 0;\n        vector<WindowCand> all;\n        int bestLen = INF;\n\n        for (int r = 0; r < T; ++r) {\n            int id = ids[r];\n            if (id != -1) {\n                if (cnt[id]++ == 0) ++covered;\n            }\n\n            while (covered == M) {\n                while (l <= r && (ids[l] == -1 || cnt[ids[l]] > 1)) {\n                    if (ids[l] != -1) --cnt[ids[l]];\n                    ++l;\n                }\n                int cl = l;\n                int cr = r + 4;\n                int len = cr - cl + 1;\n                bestLen = min(bestLen, len);\n                all.push_back({cl, cr, len, approxCostSub(cl, cr)});\n\n                if (ids[l] != -1) {\n                    if (--cnt[ids[l]] == 0) --covered;\n                }\n                ++l;\n            }\n        }\n\n        if (all.empty()) {\n            return {{0, L - 1, L, approxCostSub(0, L - 1)}};\n        }\n\n        vector<WindowCand> cand;\n        for (auto &w : all) {\n            if (w.len <= bestLen + 3) cand.push_back(w);\n        }\n        sort(cand.begin(), cand.end());\n\n        vector<WindowCand> res;\n        for (auto &w : cand) {\n            bool dup = false;\n            for (auto &u : res) {\n                if (u.l == w.l && u.r == w.r) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                res.push_back(w);\n                if ((int)res.size() >= keepK) break;\n            }\n        }\n\n        bool hasWhole = false;\n        for (auto &w : res) {\n            if (w.l == 0 && w.r == L - 1) hasWhole = true;\n        }\n        if (!hasWhole) {\n            res.push_back({0, L - 1, L, approxCostSub(0, L - 1)});\n        }\n        return res;\n    }\n\n    pair<int, vector<pair<int,int>>> exact_positions_for_string(const string& s) {\n        int L = (int)s.size();\n        vector<vector<int16_t>> parent(L);\n        vector<int> dp, ndp;\n        const vector<pair<int,int>>* prevList = nullptr;\n\n        for (int t = 0; t < L; ++t) {\n            int c = s[t] - 'A';\n            const auto& curList = posByChar[c];\n            parent[t].assign(curList.size(), -1);\n            ndp.assign(curList.size(), INF);\n\n            if (t == 0) {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    ndp[j] = abs(si - curList[j].first) + abs(sj - curList[j].second) + 1;\n                }\n            } else {\n                for (int j = 0; j < (int)curList.size(); ++j) {\n                    int best = INF, bestPrev = -1;\n                    for (int i = 0; i < (int)prevList->size(); ++i) {\n                        int cand = dp[i] + dist((*prevList)[i], curList[j]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestPrev = i;\n                        }\n                    }\n                    ndp[j] = best;\n                    parent[t][j] = (int16_t)bestPrev;\n                }\n            }\n\n            dp.swap(ndp);\n            prevList = &curList;\n        }\n\n        int lastIdx = (int)(min_element(dp.begin(), dp.end()) - dp.begin());\n        int bestCost = dp[lastIdx];\n\n        vector<pair<int,int>> ops(L);\n        int idx = lastIdx;\n        for (int t = L - 1; t >= 0; --t) {\n            int c = s[t] - 'A';\n            ops[t] = posByChar[c][idx];\n            idx = parent[t][idx];\n        }\n\n        return {bestCost, ops};\n    }\n\n    void evaluate_order(\n        const vector<int>& order,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd\n    ) {\n        uint64_t ho = hash_order(order);\n        if (!seenOrd.insert(ho).second) return;\n\n        string s = build_string(order);\n        auto wins = covering_window_candidates(s, 3);\n\n        for (auto &w : wins) {\n            string sub = s.substr(w.l, w.len);\n            size_t hs = hash<string>{}(sub);\n            if (!seenSub.insert(hs).second) continue;\n\n            auto [cost, ops] = exact_positions_for_string(sub);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestOps = move(ops);\n            }\n        }\n    }\n\n    void try_objective(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int relocIter,\n        int adjIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            auto order = build_order_cheapest_insertion(a, b, startC, edgeC);\n            order = polish_order(move(order), startC, edgeC, relocIter, adjIter);\n            evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n        }\n    }\n\n    void try_objective_hybrid(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startBuild,\n        const vector<vector<int>>& edgeBuild,\n        int pairLimit,\n        int buildRelocIter,\n        int buildAdjIter,\n        const vector<int>& startPolish,\n        const vector<vector<int>>& edgePolish,\n        int polishRelocIter,\n        int polishAdjIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            auto order = build_order_cheapest_insertion(a, b, startBuild, edgeBuild);\n            order = polish_order(move(order), startBuild, edgeBuild, buildRelocIter, buildAdjIter);\n            order = polish_order(move(order), startPolish, edgePolish, polishRelocIter, polishAdjIter);\n            evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n        }\n    }\n\n    void try_regret_objective(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int relocIter,\n        int adjIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            auto order = build_order_regret_insertion(a, b, startC, edgeC);\n            order = polish_order(move(order), startC, edgeC, relocIter, adjIter);\n            evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n        }\n    }\n\n    void try_regret_objective_hybrid(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startBuild,\n        const vector<vector<int>>& edgeBuild,\n        int pairLimit,\n        int buildRelocIter,\n        int buildAdjIter,\n        const vector<int>& startPolish,\n        const vector<vector<int>>& edgePolish,\n        int polishRelocIter,\n        int polishAdjIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            auto order = build_order_regret_insertion(a, b, startBuild, edgeBuild);\n            order = polish_order(move(order), startBuild, edgeBuild, buildRelocIter, buildAdjIter);\n            order = polish_order(move(order), startPolish, edgePolish, polishRelocIter, polishAdjIter);\n            evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n        }\n    }\n\n    void try_randomized_objective(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startC,\n        const vector<vector<int>>& edgeC,\n        int pairLimit,\n        int triesPerPair,\n        int relocIter,\n        int adjIter,\n        int topK,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd,\n        mt19937& rng\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            for (int t = 0; t < triesPerPair; ++t) {\n                if (timer.elapsed() > TL) return;\n                auto order = build_order_randomized_insertion(a, b, startC, edgeC, topK, rng);\n                order = polish_order(move(order), startC, edgeC, relocIter, adjIter);\n                evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n            }\n        }\n    }\n\n    void try_randomized_objective_hybrid(\n        const vector<pair<int,int>>& pairs,\n        const vector<int>& startBuild,\n        const vector<vector<int>>& edgeBuild,\n        int pairLimit,\n        int triesPerPair,\n        int buildRelocIter,\n        int buildAdjIter,\n        int topK,\n        const vector<int>& startPolish,\n        const vector<vector<int>>& edgePolish,\n        int polishRelocIter,\n        int polishAdjIter,\n        int& bestCost,\n        vector<pair<int,int>>& bestOps,\n        unordered_set<size_t>& seenSub,\n        unordered_set<uint64_t>& seenOrd,\n        mt19937& rng\n    ) {\n        int use = min(pairLimit, (int)pairs.size());\n        for (int idx = 0; idx < use; ++idx) {\n            if (timer.elapsed() > TL) return;\n            int a = pairs[idx].first;\n            int b = pairs[idx].second;\n\n            for (int t = 0; t < triesPerPair; ++t) {\n                if (timer.elapsed() > TL) return;\n                auto order = build_order_randomized_insertion(a, b, startBuild, edgeBuild, topK, rng);\n                order = polish_order(move(order), startBuild, edgeBuild, buildRelocIter, buildAdjIter);\n                order = polish_order(move(order), startPolish, edgePolish, polishRelocIter, polishAdjIter);\n                evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n            }\n        }\n    }\n\n    void solve() {\n        preprocess();\n        timer.reset();\n\n        uint64_t seed = 88172645463325252ULL;\n        seed ^= (uint64_t)si * 1000003ULL + (uint64_t)sj * 10007ULL;\n        for (auto &w : words) for (char c : w) seed = seed * 1315423911ULL + (unsigned)c;\n        mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n        int bestCost = INF;\n        vector<pair<int,int>> bestOps;\n        unordered_set<size_t> seenSub;\n        unordered_set<uint64_t> seenOrd;\n        seenSub.reserve(256);\n        seenOrd.reserve(200);\n\n        vector<int> startMix1(M), startMix2(M);\n        vector<vector<int>> edgeMix1(M, vector<int>(M, 0));\n        vector<vector<int>> edgeMix2(M, vector<int>(M, 0));\n        for (int i = 0; i < M; ++i) {\n            startMix1[i] = startApprox[i] + startLen[i];\n            startMix2[i] = startApprox[i] + 2 * startLen[i];\n            for (int j = 0; j < M; ++j) {\n                edgeMix1[i][j] = edgeApprox[i][j] + edgeLen[i][j];\n                edgeMix2[i][j] = edgeApprox[i][j] + 2 * edgeLen[i][j];\n            }\n        }\n\n        if (M == 1) {\n            auto [cost, ops] = exact_positions_for_string(words[0]);\n            (void)cost;\n            bestOps = move(ops);\n        } else {\n            try_objective(pairsApprox, startApprox, edgeApprox, 20, 200, 40,\n                          bestCost, bestOps, seenSub, seenOrd);\n\n            if (timer.elapsed() <= 1.02) {\n                try_regret_objective(pairsApprox, startApprox, edgeApprox, 4, 120, 30,\n                                     bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.14) {\n                try_randomized_objective(pairsApprox, startApprox, edgeApprox, 3, 2, 80, 25, 3,\n                                         bestCost, bestOps, seenSub, seenOrd, rng);\n            }\n\n            if (timer.elapsed() <= 1.22) {\n                try_objective_hybrid(pairsMix1, startMix1, edgeMix1, 3, 70, 20,\n                                     startApprox, edgeApprox, 40, 20,\n                                     bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.32) {\n                try_objective_hybrid(pairsMix2, startMix2, edgeMix2, 4, 110, 25,\n                                     startApprox, edgeApprox, 50, 20,\n                                     bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.40) {\n                try_regret_objective_hybrid(pairsMix2, startMix2, edgeMix2, 2, 80, 20,\n                                            startApprox, edgeApprox, 40, 20,\n                                            bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.48) {\n                try_randomized_objective_hybrid(pairsMix1, startMix1, edgeMix1, 2, 1, 50, 15, 3,\n                                                startApprox, edgeApprox, 30, 15,\n                                                bestCost, bestOps, seenSub, seenOrd, rng);\n            }\n            if (timer.elapsed() <= 1.54) {\n                try_randomized_objective_hybrid(pairsMix2, startMix2, edgeMix2, 1, 1, 55, 15, 3,\n                                                startApprox, edgeApprox, 30, 15,\n                                                bestCost, bestOps, seenSub, seenOrd, rng);\n            }\n\n            if (timer.elapsed() <= 1.62) {\n                try_objective(pairsLen, startLen, edgeLen, 12, 160, 30,\n                              bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.70) {\n                try_regret_objective(pairsLen, startLen, edgeLen, 2, 90, 20,\n                                     bestCost, bestOps, seenSub, seenOrd);\n            }\n            if (timer.elapsed() <= 1.81) {\n                int use = min(12, (int)pairsLen.size());\n                for (int idx = 0; idx < use; ++idx) {\n                    if (timer.elapsed() > TL) break;\n                    int a = pairsLen[idx].first;\n                    int b = pairsLen[idx].second;\n\n                    auto order = build_order_cheapest_insertion(a, b, startLen, edgeLen);\n                    order = polish_order(move(order), startLen, edgeLen, 120, 25);\n                    order = polish_order(move(order), startApprox, edgeApprox, 80, 20);\n                    evaluate_order(order, bestCost, bestOps, seenSub, seenOrd);\n                }\n            }\n\n            if (timer.elapsed() <= 1.85) {\n                try_randomized_objective(pairsLen, startLen, edgeLen, 2, 1, 70, 20, 3,\n                                         bestCost, bestOps, seenSub, seenOrd, rng);\n            }\n            if (timer.elapsed() <= 1.88) {\n                try_randomized_objective(pairsApprox, startApprox, edgeApprox, 1, 2, 60, 20, 4,\n                                         bestCost, bestOps, seenSub, seenOrd, rng);\n            }\n        }\n\n        if (bestOps.empty()) {\n            string s;\n            for (auto& w : words) s += w;\n            auto [cost, ops] = exact_positions_for_string(s);\n            (void)cost;\n            bestOps = move(ops);\n        }\n\n        for (auto [i, j] : bestOps) {\n            cout << i << ' ' << j << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M;\n    cin >> solver.si >> solver.sj;\n    solver.board.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.board[i];\n    solver.words.resize(solver.M);\n    for (int i = 0; i < solver.M; ++i) cin >> solver.words[i];\n\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 20;\nstatic constexpr int MAXC = 400;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ull;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n} rng;\n\nstruct Placement {\n    vector<uint16_t> cells;\n    bitset<MAXC> mask;\n    vector<uint8_t> contrib;\n    vector<uint16_t> drill_ids;\n    bool valid = true;\n};\n\nstruct Field {\n    vector<pair<int,int>> shape;\n    vector<Placement> ps;\n    int valid_count = 0;\n};\n\nstruct SavedState {\n    array<short, MAXM> choice{};\n    int exact_err = INT_MAX;\n    double noisy = 1e100;\n};\n\nstruct SearchState {\n    array<short, MAXM> choice{};\n    vector<int> feat;\n    vector<int> pred;\n    int exact_err = 0;\n    double noisy = 0.0;\n};\n\nstruct GuessCand {\n    vector<char> occ;\n    vector<int> cells;\n    int freq = 0;\n    double best_noisy = 1e100;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n\n    vector<Field> fields;\n\n    int rb[5], cb[5];\n    int block_id[MAXN][MAXN];\n\n    int Q = 0;\n    vector<vector<int>> query_cells;\n    vector<bitset<MAXC>> query_masks;\n    vector<double> estQ, wQ;\n    vector<int> qSize;\n\n    vector<vector<pair<uint8_t, uint16_t>>> coverList;\n\n    vector<int> drill_cells;\n    vector<int> drill_obs;\n    vector<int> cell_to_drill;\n    vector<int> exact_v;\n\n    vector<int> mark, chg, aff;\n    int iter_mark = 1;\n\n    int wrong_guess_count = 0;\n    static constexpr int GUESS_BUDGET = 3;\n    vector<vector<int>> guessed_answers;\n\n    chrono::steady_clock::time_point st;\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool better_pair(int e1, double n1, int e2, double n2) const {\n        if (e1 != e2) return e1 < e2;\n        return n1 + 1e-12 < n2;\n    }\n\n    int ask_divination(const vector<int>& cells) {\n        cout << \"q \" << cells.size();\n        for (int id : cells) cout << ' ' << id / N << ' ' << id % N;\n        cout << endl;\n        cout.flush();\n        int y;\n        cin >> y;\n        return y;\n    }\n\n    int ask_drill(int cell) {\n        cout << \"q 1 \" << cell / N << ' ' << cell % N << endl;\n        cout.flush();\n        int v;\n        cin >> v;\n        return v;\n    }\n\n    bool ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int id : cells) cout << ' ' << id / N << ' ' << id % N;\n        cout << endl;\n        cout.flush();\n        int ok;\n        cin >> ok;\n        return ok == 1;\n    }\n\n    bool same_cells(const vector<int>& a, const vector<int>& b) const {\n        return a == b;\n    }\n\n    bool already_guessed(const vector<int>& cells) const {\n        for (const auto &g : guessed_answers) {\n            if (same_cells(g, cells)) return true;\n        }\n        return false;\n    }\n\n    bool try_guess_answer(const vector<int>& cells) {\n        if (wrong_guess_count >= GUESS_BUDGET) return false;\n        if (already_guessed(cells)) return false;\n        guessed_answers.push_back(cells);\n        bool ok = ask_answer(cells);\n        if (ok) return true;\n        wrong_guess_count++;\n        return false;\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        alpha = 1.0 - 2.0 * eps;\n        C = N * N;\n\n        fields.resize(M);\n        for (int k = 0; k < M; ++k) {\n            int d;\n            cin >> d;\n            fields[k].shape.resize(d);\n            for (int t = 0; t < d; ++t) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].shape[t] = {i, j};\n            }\n        }\n\n        coverList.assign(C, {});\n        cell_to_drill.assign(C, -1);\n        exact_v.assign(C, -1);\n    }\n\n    void build_blocks() {\n        for (int t = 0; t <= 4; ++t) {\n            rb[t] = (long long)t * N / 4;\n            cb[t] = (long long)t * N / 4;\n        }\n        for (int i = 0; i < N; ++i) {\n            int bi = 0;\n            while (!(rb[bi] <= i && i < rb[bi + 1])) ++bi;\n            for (int j = 0; j < N; ++j) {\n                int bj = 0;\n                while (!(cb[bj] <= j && j < cb[bj + 1])) ++bj;\n                block_id[i][j] = bi * 4 + bj;\n            }\n        }\n    }\n\n    void add_query_set(const vector<int>& cells) {\n        if ((int)cells.size() < 2) return;\n        bitset<MAXC> bs;\n        for (int id : cells) bs.set(id);\n        query_cells.push_back(cells);\n        query_masks.push_back(bs);\n    }\n\n    void build_query_sets() {\n        query_cells.clear();\n        query_masks.clear();\n\n        int mode = 0;\n        if (M <= 5 && eps <= 0.15) mode = 3;\n        else if (M <= 8 && eps <= 0.12) mode = 2;\n        else if ((M <= 12 && eps <= 0.10) || (M <= 15 && eps <= 0.05)) mode = 1;\n        else mode = 0;\n\n        if (mode >= 2) {\n            for (int i = 0; i < N; ++i) {\n                vector<int> cells;\n                for (int j = 0; j < N; ++j) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n            for (int j = 0; j < N; ++j) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) cells.push_back(i * N + j);\n                add_query_set(cells);\n            }\n        }\n\n        if (mode >= 1) {\n            for (int bi = 0; bi < 4; ++bi) {\n                for (int bj = 0; bj < 4; ++bj) {\n                    vector<int> cells;\n                    for (int i = rb[bi]; i < rb[bi + 1]; ++i) {\n                        for (int j = cb[bj]; j < cb[bj + 1]; ++j) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    add_query_set(cells);\n                }\n            }\n        } else {\n            for (int bi = 0; bi < 2; ++bi) {\n                for (int bj = 0; bj < 2; ++bj) {\n                    int r0 = (long long)bi * N / 2;\n                    int r1 = (long long)(bi + 1) * N / 2;\n                    int c0 = (long long)bj * N / 2;\n                    int c1 = (long long)(bj + 1) * N / 2;\n                    vector<int> cells;\n                    for (int i = r0; i < r1; ++i) {\n                        for (int j = c0; j < c1; ++j) cells.push_back(i * N + j);\n                    }\n                    add_query_set(cells);\n                }\n            }\n        }\n\n        if (mode == 3) {\n            for (int t = 0; t < 4; ++t) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        int f = 0;\n                        if (t == 0) f = ((i + j) & 1);\n                        if (t == 1) f = (i & 1);\n                        if (t == 2) f = (j & 1);\n                        if (t == 3) f = (((i / 2) + (j / 2)) & 1);\n                        if (f) cells.push_back(i * N + j);\n                    }\n                }\n                if ((int)cells.size() >= 2 && (int)cells.size() < C) add_query_set(cells);\n            }\n        }\n\n        if (mode <= 1) {\n            for (int t = 0; t < 2; ++t) {\n                vector<int> cells;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        int f = 0;\n                        if (t == 0) f = ((i + j) & 1);\n                        if (t == 1) f = (((i / 2) + (j / 2)) & 1);\n                        if (f) cells.push_back(i * N + j);\n                    }\n                }\n                if ((int)cells.size() >= 2 && (int)cells.size() < C) add_query_set(cells);\n            }\n        }\n\n        Q = (int)query_cells.size();\n        estQ.assign(Q, 0.0);\n        wQ.assign(Q, 0.0);\n        qSize.assign(Q, 0);\n    }\n\n    void ask_initial_queries() {\n        for (int q = 0; q < Q; ++q) {\n            int y = ask_divination(query_cells[q]);\n            int k = (int)query_cells[q].size();\n            qSize[q] = k;\n            estQ[q] = (y - k * eps) / alpha;\n            double var_est = (k * eps * (1.0 - eps)) / (alpha * alpha) + 0.5;\n            wQ[q] = 1.0 / var_est;\n        }\n    }\n\n    void enumerate_placements() {\n        for (int k = 0; k < M; ++k) {\n            int max_i = 0, max_j = 0;\n            for (auto [i, j] : fields[k].shape) {\n                max_i = max(max_i, i);\n                max_j = max(max_j, j);\n            }\n\n            for (int di = 0; di + max_i < N; ++di) {\n                for (int dj = 0; dj + max_j < N; ++dj) {\n                    Placement p;\n                    p.contrib.assign(Q, 0);\n\n                    for (auto [si, sj] : fields[k].shape) {\n                        int i = di + si;\n                        int j = dj + sj;\n                        int id = i * N + j;\n                        p.cells.push_back((uint16_t)id);\n                        p.mask.set(id);\n                    }\n\n                    for (int q = 0; q < Q; ++q) {\n                        uint8_t c = 0;\n                        for (int id : p.cells) c += (uint8_t)query_masks[q].test(id);\n                        p.contrib[q] = c;\n                    }\n\n                    int idx = (int)fields[k].ps.size();\n                    for (int id : p.cells) coverList[id].push_back({(uint8_t)k, (uint16_t)idx});\n                    fields[k].ps.push_back(std::move(p));\n                }\n            }\n            fields[k].valid_count = (int)fields[k].ps.size();\n        }\n    }\n\n    bool usable_placement(int k, int p) const {\n        return fields[k].ps[p].valid;\n    }\n\n    bool invalidate_field_by_cover_state(int k, int cell, bool must_cover) {\n        bool changed = false;\n        for (auto &pl : fields[k].ps) {\n            if (!pl.valid) continue;\n            bool cov = pl.mask.test(cell);\n            if (cov != must_cover) {\n                pl.valid = false;\n                fields[k].valid_count--;\n                changed = true;\n            }\n        }\n        return changed;\n    }\n\n    void register_drill(int cell, int v) {\n        exact_v[cell] = v;\n        if (cell_to_drill[cell] == -1) {\n            int idx = (int)drill_cells.size();\n            cell_to_drill[cell] = idx;\n            drill_cells.push_back(cell);\n            drill_obs.push_back(v);\n\n            mark.resize(drill_cells.size(), 0);\n            chg.resize(drill_cells.size(), 0);\n\n            for (auto [fk, pi] : coverList[cell]) {\n                fields[fk].ps[pi].drill_ids.push_back((uint16_t)idx);\n            }\n        } else {\n            drill_obs[cell_to_drill[cell]] = v;\n        }\n\n        if (v == 0) {\n            for (auto [fk, pi] : coverList[cell]) {\n                auto &pl = fields[fk].ps[pi];\n                if (pl.valid) {\n                    pl.valid = false;\n                    fields[fk].valid_count--;\n                }\n            }\n        }\n    }\n\n    void propagate_constraints() {\n        if (drill_cells.empty()) return;\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int did = 0; did < (int)drill_cells.size(); ++did) {\n                int cell = drill_cells[did];\n                int req = drill_obs[did];\n\n                int sure = 0, poss = 0;\n                vector<uint8_t> state(M, 0);\n\n                for (int k = 0; k < M; ++k) {\n                    bool any0 = false, any1 = false;\n                    for (const auto &pl : fields[k].ps) {\n                        if (!pl.valid) continue;\n                        bool cov = pl.mask.test(cell);\n                        if (cov) any1 = true;\n                        else any0 = true;\n                        if (any0 && any1) break;\n                    }\n                    if (!any0 && !any1) return;\n\n                    if (any1 && !any0) {\n                        state[k] = 1;\n                        sure++;\n                        poss++;\n                    } else if (any1 && any0) {\n                        state[k] = 2;\n                        poss++;\n                    } else {\n                        state[k] = 3;\n                    }\n                }\n\n                if (sure > req || poss < req) return;\n\n                if (sure == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) changed |= invalidate_field_by_cover_state(k, cell, false);\n                    }\n                }\n                if (poss == req) {\n                    for (int k = 0; k < M; ++k) {\n                        if (state[k] == 2) changed |= invalidate_field_by_cover_state(k, cell, true);\n                    }\n                }\n            }\n        }\n    }\n\n    bool all_fields_unique(vector<int>& ans_cells) const {\n        bitset<MAXC> uni;\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count != 1) return false;\n            for (const auto &pl : fields[k].ps) {\n                if (pl.valid) {\n                    uni |= pl.mask;\n                    break;\n                }\n            }\n        }\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (uni.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    bitset<MAXC> compute_possible_union() const {\n        bitset<MAXC> uni;\n        for (int k = 0; k < M; ++k) {\n            for (const auto &pl : fields[k].ps) if (pl.valid) uni |= pl.mask;\n        }\n        return uni;\n    }\n\n    vector<int> possible_union_unknown_cells() const {\n        auto uni = compute_possible_union();\n        vector<int> res;\n        for (int id = 0; id < C; ++id) {\n            if (uni.test(id) && exact_v[id] == -1) res.push_back(id);\n        }\n        return res;\n    }\n\n    double initial_noisy0() const {\n        double s = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            double r = -estQ[q];\n            s += wQ[q] * r * r;\n        }\n        return s;\n    }\n\n    void calc_delta_parts(const SearchState& s, int field_idx, int newp, int &dExact, double &dNoisy) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) {\n            dExact = 0;\n            dNoisy = 0.0;\n            return;\n        }\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        dNoisy = 0.0;\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            dNoisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n        }\n\n        dExact = 0;\n        if (drill_cells.empty()) return;\n\n        ++iter_mark;\n        if (iter_mark == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            iter_mark = 1;\n        }\n        aff.clear();\n\n        if (oldpl) {\n            for (int id : oldpl->drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]--;\n            }\n        }\n        for (int id : newpl.drill_ids) {\n            if (mark[id] != iter_mark) {\n                mark[id] = iter_mark;\n                chg[id] = 0;\n                aff.push_back(id);\n            }\n            chg[id]++;\n        }\n\n        for (int id : aff) {\n            int oc = s.pred[id];\n            int nc = oc + chg[id];\n            int obs = drill_obs[id];\n            dExact += (nc - obs) * (nc - obs) - (oc - obs) * (oc - obs);\n        }\n    }\n\n    void apply_change(SearchState& s, int field_idx, int newp) {\n        int oldp = s.choice[field_idx];\n        if (oldp == newp) return;\n\n        const Placement* oldpl = (oldp == -1 ? nullptr : &fields[field_idx].ps[oldp]);\n        const Placement& newpl = fields[field_idx].ps[newp];\n\n        for (int q = 0; q < Q; ++q) {\n            int d = (int)newpl.contrib[q] - (oldpl ? (int)oldpl->contrib[q] : 0);\n            if (!d) continue;\n            double r = (double)s.feat[q] - estQ[q];\n            s.noisy += wQ[q] * (2.0 * r * d + 1.0 * d * d);\n            s.feat[q] += d;\n        }\n\n        if (!drill_cells.empty()) {\n            ++iter_mark;\n            if (iter_mark == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                iter_mark = 1;\n            }\n            aff.clear();\n\n            if (oldpl) {\n                for (int id : oldpl->drill_ids) {\n                    if (mark[id] != iter_mark) {\n                        mark[id] = iter_mark;\n                        chg[id] = 0;\n                        aff.push_back(id);\n                    }\n                    chg[id]--;\n                }\n            }\n            for (int id : newpl.drill_ids) {\n                if (mark[id] != iter_mark) {\n                    mark[id] = iter_mark;\n                    chg[id] = 0;\n                    aff.push_back(id);\n                }\n                chg[id]++;\n            }\n\n            for (int id : aff) {\n                int oc = s.pred[id];\n                int obs = drill_obs[id];\n                s.exact_err -= (oc - obs) * (oc - obs);\n                s.pred[id] += chg[id];\n                int nc = s.pred[id];\n                s.exact_err += (nc - obs) * (nc - obs);\n            }\n        }\n\n        s.choice[field_idx] = (short)newp;\n    }\n\n    SearchState greedy_random_init() {\n        SearchState s;\n        s.choice.fill(-1);\n        s.feat.assign(Q, 0);\n        s.pred.assign(drill_cells.size(), 0);\n        s.exact_err = 0;\n        for (int obs : drill_obs) s.exact_err += obs * obs;\n        s.noisy = initial_noisy0();\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n        for (int k : order) {\n            struct Cand { int p; int e; double n; };\n            Cand best[4];\n            int bsz = 0;\n\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                int de;\n                double dn;\n                calc_delta_parts(s, k, p, de, dn);\n                int ne = s.exact_err + de;\n                double nn = s.noisy + dn;\n                Cand cur{p, ne, nn};\n\n                int pos = bsz;\n                for (int t = 0; t < bsz; ++t) {\n                    if (better_pair(cur.e, cur.n, best[t].e, best[t].n)) {\n                        pos = t;\n                        break;\n                    }\n                }\n                if (pos < 4) {\n                    for (int t = min(3, bsz); t > pos; --t) best[t] = best[t - 1];\n                    best[pos] = cur;\n                    if (bsz < 4) ++bsz;\n                }\n            }\n\n            if (bsz == 0) continue;\n            int pick = 0;\n            if (bsz >= 2) {\n                int r = rng.next_int(0, min(6, bsz * 2) - 1);\n                pick = min(r / 2, bsz - 1);\n            }\n            apply_change(s, k, best[pick].p);\n        }\n        return s;\n    }\n\n    void local_descent(SearchState& s, int max_sweeps = 4) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < max_sweeps; ++sw) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next_u64()));\n\n            for (int k : order) {\n                int bestp = s.choice[k];\n                int beste = s.exact_err;\n                double bestn = s.noisy;\n\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (!usable_placement(k, p)) continue;\n                    int de;\n                    double dn;\n                    calc_delta_parts(s, k, p, de, dn);\n                    int ne = s.exact_err + de;\n                    double nn = s.noisy + dn;\n                    if (better_pair(ne, nn, beste, bestn)) {\n                        beste = ne;\n                        bestn = nn;\n                        bestp = p;\n                    }\n                }\n                if (bestp != s.choice[k]) {\n                    apply_change(s, k, bestp);\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    static bool same_choice(const SavedState& a, const SavedState& b, int M) {\n        for (int i = 0; i < M; ++i) if (a.choice[i] != b.choice[i]) return false;\n        return true;\n    }\n\n    void add_saved(vector<SavedState>& top, const SearchState& s, int keep = 10) {\n        SavedState cur;\n        cur.choice = s.choice;\n        cur.exact_err = s.exact_err;\n        cur.noisy = s.noisy;\n\n        for (auto &x : top) {\n            if (same_choice(x, cur, M)) {\n                if (better_pair(cur.exact_err, cur.noisy, x.exact_err, x.noisy)) x = cur;\n                return;\n            }\n        }\n\n        top.push_back(cur);\n        sort(top.begin(), top.end(), [&](const SavedState& a, const SavedState& b) {\n            return better_pair(a.exact_err, a.noisy, b.exact_err, b.noisy);\n        });\n        if ((int)top.size() > keep) top.resize(keep);\n    }\n\n    vector<SavedState> search_states(int restarts) {\n        vector<SavedState> top;\n        for (int it = 0; it < restarts; ++it) {\n            if (elapsed_ms() > 2650.0) break;\n            SearchState s = greedy_random_init();\n            local_descent(s, 4);\n            add_saved(top, s, 10);\n        }\n        return top;\n    }\n\n    vector<char> union_from_choice(const array<short, MAXM>& choice) const {\n        vector<char> occ(C, 0);\n        for (int k = 0; k < M; ++k) {\n            int p = choice[k];\n            if (p < 0) continue;\n            for (int id : fields[k].ps[p].cells) occ[id] = 1;\n        }\n        return occ;\n    }\n\n    vector<GuessCand> collect_guess_candidates(const vector<SavedState>& top) const {\n        vector<GuessCand> cands;\n        for (const auto &st : top) {\n            if (st.exact_err != 0) continue;\n            auto occ = union_from_choice(st.choice);\n\n            int found = -1;\n            for (int i = 0; i < (int)cands.size(); ++i) {\n                if (cands[i].occ == occ) {\n                    found = i;\n                    break;\n                }\n            }\n            if (found == -1) {\n                GuessCand gc;\n                gc.occ = occ;\n                gc.freq = 1;\n                gc.best_noisy = st.noisy;\n                cands.push_back(std::move(gc));\n            } else {\n                cands[found].freq++;\n                cands[found].best_noisy = min(cands[found].best_noisy, st.noisy);\n            }\n        }\n\n        for (auto &gc : cands) {\n            gc.cells.clear();\n            for (int id = 0; id < C; ++id) if (gc.occ[id]) gc.cells.push_back(id);\n        }\n\n        sort(cands.begin(), cands.end(), [&](const GuessCand& a, const GuessCand& b) {\n            if (a.freq != b.freq) return a.freq > b.freq;\n            return a.best_noisy < b.best_noisy;\n        });\n        return cands;\n    }\n\n    bool exact_deduce_union(vector<int>& ans_cells) {\n        if (elapsed_ms() > 2520.0) return false;\n        for (int k = 0; k < M; ++k) if (fields[k].valid_count <= 0) return false;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (fields[a].valid_count != fields[b].valid_count) return fields[a].valid_count < fields[b].valid_count;\n            return a < b;\n        });\n\n        double log_prod = 0.0;\n        for (int k : order) log_prod += log((double)max(1, fields[k].valid_count));\n        if (log_prod > log(5.0e6)) return false;\n\n        int D = (int)drill_cells.size();\n        vector<vector<int>> valid_list(M);\n\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (usable_placement(k, p)) valid_list[t].push_back(p);\n            }\n            if (valid_list[t].empty()) return false;\n        }\n\n        vector<vector<int>> can_cover(M, vector<int>(D, 0));\n        for (int t = 0; t < M; ++t) {\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                for (int did : fields[k].ps[p].drill_ids) can_cover[t][did] = 1;\n            }\n        }\n\n        vector<vector<int>> rem_max(M + 1, vector<int>(D, 0));\n        for (int t = M - 1; t >= 0; --t) {\n            for (int d = 0; d < D; ++d) rem_max[t][d] = rem_max[t + 1][d] + can_cover[t][d];\n        }\n\n        array<short, MAXM> choice;\n        choice.fill(-1);\n        vector<int> cur(D, 0);\n\n        long long nodes = 0;\n        bool aborted = false;\n        int solutions = 0;\n        bool same_union = true;\n        bitset<MAXC> common_union;\n        bool has_common = false;\n\n        function<void(int)> dfs = [&](int t) {\n            if (aborted) return;\n            if (++nodes > 3500000LL || elapsed_ms() > 2870.0) {\n                aborted = true;\n                return;\n            }\n\n            for (int d = 0; d < D; ++d) {\n                if (cur[d] > drill_obs[d]) return;\n                if (cur[d] + rem_max[t][d] < drill_obs[d]) return;\n            }\n\n            if (t == M) {\n                for (int d = 0; d < D; ++d) if (cur[d] != drill_obs[d]) return;\n                solutions++;\n                bitset<MAXC> uni;\n                for (int kk = 0; kk < M; ++kk) {\n                    int p = choice[kk];\n                    uni |= fields[kk].ps[p].mask;\n                }\n                if (!has_common) {\n                    common_union = uni;\n                    has_common = true;\n                } else if (common_union != uni) {\n                    same_union = false;\n                }\n                return;\n            }\n\n            int k = order[t];\n            for (int p : valid_list[t]) {\n                auto &pl = fields[k].ps[p];\n                choice[k] = (short)p;\n                for (int did : pl.drill_ids) cur[did]++;\n                dfs(t + 1);\n                for (int did : pl.drill_ids) cur[did]--;\n                if (aborted) return;\n            }\n        };\n\n        dfs(0);\n\n        if (aborted || solutions == 0 || !same_union) return false;\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (common_union.test(id)) ans_cells.push_back(id);\n        return true;\n    }\n\n    bool confident_answer_from_top(const vector<SavedState>& top, vector<int>& ans_cells) {\n        if (top.empty() || top[0].exact_err != 0) return false;\n\n        vector<int> idxs;\n        for (int i = 0; i < (int)top.size(); ++i) {\n            if (top[i].exact_err == 0) idxs.push_back(i);\n        }\n        if ((int)idxs.size() < 4) return false;\n\n        int use = min(6, (int)idxs.size());\n        auto base = union_from_choice(top[idxs[0]].choice);\n        for (int t = 1; t < use; ++t) {\n            auto u = union_from_choice(top[idxs[t]].choice);\n            if (u != base) return false;\n        }\n\n        ans_cells.clear();\n        for (int id = 0; id < C; ++id) if (base[id]) ans_cells.push_back(id);\n        return true;\n    }\n\n    bool try_guess_from_top_candidates(const vector<SavedState>& top, int rem_possible, bool final_phase) {\n        if (wrong_guess_count >= GUESS_BUDGET) return false;\n        if (rem_possible < 70 && !final_phase) return false;\n\n        auto cands = collect_guess_candidates(top);\n        if (cands.empty()) return false;\n\n        int tries = 0;\n        for (int i = 0; i < (int)cands.size(); ++i) {\n            bool ok_to_try = false;\n            if (!final_phase) {\n                if (i == 0 && cands[i].freq >= 3) ok_to_try = true;\n                if (i == 0 && cands.size() == 1 && cands[i].freq >= 2) ok_to_try = true;\n            } else {\n                if (i < 2) ok_to_try = true;\n            }\n            if (!ok_to_try) continue;\n            if (already_guessed(cands[i].cells)) continue;\n            if (try_guess_answer(cands[i].cells)) return true;\n            tries++;\n            if (!final_phase && tries >= 1) break;\n            if (final_phase && tries >= 2) break;\n            if (wrong_guess_count >= GUESS_BUDGET) break;\n        }\n        return false;\n    }\n\n    int select_drill_cell_from_states(const vector<SavedState>& top) {\n        auto possible = compute_possible_union();\n        vector<double> best_score(C, -1e100);\n\n        vector<int> near_pos(C, 0);\n        for (int t = 0; t < (int)drill_cells.size(); ++t) {\n            if (drill_obs[t] <= 0) continue;\n            int id = drill_cells[t];\n            int x = id / N, y = id % N;\n            static const int dx[4] = {-1, 1, 0, 0};\n            static const int dy[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; ++dir) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                    int nid = nx * N + ny;\n                    if (exact_v[nid] == -1) near_pos[nid]++;\n                }\n            }\n        }\n\n        if (!top.empty()) {\n            int best_exact = top[0].exact_err;\n            vector<int> cand_idxs;\n            for (int i = 0; i < (int)top.size(); ++i) {\n                if (top[i].exact_err == best_exact) cand_idxs.push_back(i);\n            }\n            if ((int)cand_idxs.size() >= 2) {\n                int S = min(8, (int)cand_idxs.size());\n                vector<double> sum(C, 0.0), sq(C, 0.0), occ(C, 0.0);\n\n                for (int t = 0; t < S; ++t) {\n                    const auto& ch = top[cand_idxs[t]].choice;\n                    vector<int> cnt(C, 0);\n                    for (int k = 0; k < M; ++k) {\n                        int p = ch[k];\n                        if (p < 0) continue;\n                        for (int id : fields[k].ps[p].cells) cnt[id]++;\n                    }\n                    for (int id = 0; id < C; ++id) {\n                        if (exact_v[id] != -1 || !possible.test(id)) continue;\n                        sum[id] += cnt[id];\n                        sq[id] += 1.0 * cnt[id] * cnt[id];\n                        occ[id] += (cnt[id] > 0 ? 1.0 : 0.0);\n                    }\n                }\n\n                for (int id = 0; id < C; ++id) {\n                    if (exact_v[id] != -1 || !possible.test(id)) continue;\n                    double mean = sum[id] / S;\n                    double var = sq[id] / S - mean * mean;\n                    double pocc = occ[id] / S;\n                    double score = var + 0.30 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * mean;\n                    best_score[id] = max(best_score[id], score);\n                }\n            }\n        }\n\n        vector<double> pcover_sum(C, 0.0), var_sum(C, 0.0);\n        vector<int> cnt(C, 0);\n\n        for (int k = 0; k < M; ++k) {\n            if (fields[k].valid_count <= 0) continue;\n            fill(cnt.begin(), cnt.end(), 0);\n            int tot = 0;\n            for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                if (!usable_placement(k, p)) continue;\n                ++tot;\n                for (int id : fields[k].ps[p].cells) cnt[id]++;\n            }\n            if (tot == 0) continue;\n\n            for (int id = 0; id < C; ++id) {\n                if (exact_v[id] != -1 || !possible.test(id)) continue;\n                if (cnt[id] == 0) continue;\n                double pk = 1.0 * cnt[id] / tot;\n                pcover_sum[id] += pk;\n                var_sum[id] += pk * (1.0 - pk);\n            }\n        }\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1 || !possible.test(id)) continue;\n            double p0 = 1.0;\n            for (int k = 0; k < M; ++k) {\n                if (fields[k].valid_count <= 0) continue;\n                int cov = 0;\n                for (int p = 0; p < (int)fields[k].ps.size(); ++p) {\n                    if (usable_placement(k, p) && fields[k].ps[p].mask.test(id)) cov++;\n                }\n                double pk = 1.0 * cov / max(1, fields[k].valid_count);\n                p0 *= (1.0 - pk);\n            }\n            double pocc = 1.0 - p0;\n            double score = var_sum[id] + 0.40 * pocc * (1.0 - pocc) + 0.15 * near_pos[id] + 0.02 * pcover_sum[id];\n            best_score[id] = max(best_score[id], score);\n        }\n\n        int best_cell = -1;\n        double best = -1e100;\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] != -1 || !possible.test(id)) continue;\n            if (best_score[id] > best + 1e-12) {\n                best = best_score[id];\n                best_cell = id;\n            }\n        }\n        if (best_cell != -1) return best_cell;\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1 && possible.test(id)) return id;\n        }\n        return -1;\n    }\n\n    bool should_use_search() const {\n        if (Q == 0) return false;\n        if (M <= 6) return true;\n        if (M <= 9) return true;\n        if (drill_cells.size() >= 3 && M <= 16) return true;\n        if (drill_cells.size() >= 5) return true;\n        return false;\n    }\n\n    bool finish_by_drilling_possible_union_if_tiny(int threshold) {\n        auto rem = possible_union_unknown_cells();\n        if ((int)rem.size() > threshold) return false;\n\n        for (int cell : rem) {\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        return ask_answer(ans);\n    }\n\n    bool heuristic_phase() {\n        int heuristic_limit;\n        if (M <= 4) heuristic_limit = 24;\n        else if (M <= 8) heuristic_limit = 18;\n        else if (M <= 12) heuristic_limit = 12;\n        else heuristic_limit = 8;\n        if (eps <= 0.05) heuristic_limit += 4;\n        heuristic_limit = min(28, heuristic_limit);\n\n        bool guessed_nonexact = false;\n\n        for (int step = 0; step < heuristic_limit; ++step) {\n            if (elapsed_ms() > 2800.0) break;\n\n            vector<int> ans_cells;\n\n            if (all_fields_unique(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            if (exact_deduce_union(ans_cells)) {\n                if (ask_answer(ans_cells)) return true;\n            }\n\n            int rem_possible = (int)possible_union_unknown_cells().size();\n\n            if (step >= heuristic_limit / 2) {\n                if (finish_by_drilling_possible_union_if_tiny(24)) return true;\n            }\n\n            vector<SavedState> top;\n            if (should_use_search()) {\n                int restarts;\n                if (M <= 5) restarts = 24;\n                else if (M <= 9) restarts = 14;\n                else if (M <= 14) restarts = 8;\n                else restarts = 5;\n                if (step > 0) restarts = max(4, restarts - 2);\n                if (eps <= 0.05) restarts += 2;\n                top = search_states(restarts);\n\n                if (!guessed_nonexact && confident_answer_from_top(top, ans_cells)) {\n                    guessed_nonexact = true;\n                    if (ask_answer(ans_cells)) return true;\n                }\n\n                if (try_guess_from_top_candidates(top, rem_possible, false)) return true;\n            }\n\n            int cell = select_drill_cell_from_states(top);\n            if (cell == -1) break;\n\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n            propagate_constraints();\n        }\n\n        vector<int> ans_cells;\n        if (all_fields_unique(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        if (exact_deduce_union(ans_cells)) {\n            if (ask_answer(ans_cells)) return true;\n        }\n        return false;\n    }\n\n    bool final_search_and_guess() {\n        if (wrong_guess_count >= GUESS_BUDGET) return false;\n        if (Q == 0) return false;\n        if (elapsed_ms() > 2500.0) return false;\n\n        int rem_possible = (int)possible_union_unknown_cells().size();\n        if (rem_possible < 60) return false;\n\n        int restarts;\n        if (M <= 5) restarts = 28;\n        else if (M <= 9) restarts = 18;\n        else if (M <= 14) restarts = 10;\n        else restarts = 6;\n\n        auto top = search_states(restarts);\n        return try_guess_from_top_candidates(top, rem_possible, true);\n    }\n\n    void exhaustive_finish() {\n        if (final_search_and_guess()) return;\n\n        auto rem = possible_union_unknown_cells();\n        for (int cell : rem) {\n            int v = ask_drill(cell);\n            register_drill(cell, v);\n        }\n\n        vector<int> ans;\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        if (ask_answer(ans)) return;\n\n        for (int id = 0; id < C; ++id) {\n            if (exact_v[id] == -1) {\n                int v = ask_drill(id);\n                register_drill(id, v);\n            }\n        }\n        ans.clear();\n        for (int id = 0; id < C; ++id) if (exact_v[id] > 0) ans.push_back(id);\n        ask_answer(ans);\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_blocks();\n        build_query_sets();\n        if (Q > 0) ask_initial_queries();\n        enumerate_placements();\n\n        if (heuristic_phase()) return;\n        exhaustive_finish();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct RowSol {\n    int l, r, h;\n    bool isConst = false;\n    vector<int> constWPos;          // widths by position if constant row\n    vector<vector<int>> w;          // [D][m] minimum widths if dynamic row\n    vector<int> perm;               // left-to-right order of local indices\n    vector<int> qPath;              // which position absorbs row slack on each day\n    ll vcost = INF64;\n};\n\nstruct Candidate {\n    vector<vector<Rect>> ans;\n    ll cost = INF64;\n};\n\nstruct Seed {\n    vector<pair<int,int>> parts;\n    vector<int> heights;\n    ll proxy;\n};\n\nstruct Solver {\n    int W, D, N;\n    vector<vector<int>> a;\n\n    vector<vector<int>> minH;\n    vector<ll> quickCostCache;\n    vector<unsigned char> quickCostUsed;\n\n    unordered_map<long long, int> rowCacheId;\n    vector<RowSol> rowCache;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> W >> D >> N;\n        a.assign(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\n        minH.assign(N, vector<int>(N, -1));\n\n        int SZ = N * N * (W + 1);\n        quickCostCache.assign(SZ, 0);\n        quickCostUsed.assign(SZ, 0);\n\n        rowCache.reserve(80000);\n        rowCacheId.reserve(80000);\n    }\n\n    static int divup(int x, int y) {\n        return (x + y - 1) / y;\n    }\n\n    inline int cache_id(int l, int r, int h) const {\n        return ((l * N + r) * (W + 1) + h);\n    }\n\n    inline long long row_key(int l, int r, int h) const {\n        return ((long long)l * 64 + r) * 1024 + h;\n    }\n\n    static int symdiff_count_sorted(const vector<int>& A, const vector<int>& B) {\n        int i = 0, j = 0, inter = 0;\n        while (i < (int)A.size() && j < (int)B.size()) {\n            if (A[i] == B[j]) {\n                inter++;\n                i++;\n                j++;\n            } else if (A[i] < B[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return (int)A.size() + (int)B.size() - 2 * inter;\n    }\n\n    bool feasible_seg(int l, int r, int h) const {\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int k = l; k <= r; k++) {\n                s += divup(a[d][k], h);\n                if (s > W) return false;\n            }\n        }\n        return true;\n    }\n\n    void precompute_min_heights() {\n        for (int l = 0; l < N; l++) {\n            for (int r = l; r < N; r++) {\n                if (!feasible_seg(l, r, W)) break;\n\n                int lo = 1, hi = W;\n                while (lo < hi) {\n                    int mid = (lo + hi) >> 1;\n                    if (feasible_seg(l, r, mid)) hi = mid;\n                    else lo = mid + 1;\n                }\n                minH[l][r] = lo;\n            }\n        }\n    }\n\n    // Quick row cost:\n    // - if row can be constant across days, cost = 0\n    // - else natural order, all slack goes to last rectangle\n    ll quick_row_cost(int l, int r, int h) {\n        int id = cache_id(l, r, h);\n        if (quickCostUsed[id]) return quickCostCache[id];\n        quickCostUsed[id] = 1;\n\n        int m = r - l + 1;\n\n        int sumMax = 0;\n        for (int t = 0; t < m; t++) {\n            int mx = 0;\n            for (int d = 0; d < D; d++) mx = max(mx, divup(a[d][l + t], h));\n            sumMax += mx;\n            if (sumMax > W) break;\n        }\n        if (sumMax <= W) {\n            quickCostCache[id] = 0;\n            return 0;\n        }\n\n        vector<vector<int>> cuts(D);\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int k = l; k < r; k++) {\n                cur += divup(a[d][k], h);\n                cuts[d].push_back(cur);\n            }\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            v += 1LL * h * symdiff_count_sorted(cuts[d - 1], cuts[d]);\n        }\n        quickCostCache[id] = v;\n        return v;\n    }\n\n    vector<pair<int,int>> partition_dp(int rowPenalty) {\n        vector<vector<ll>> dp(N + 1, vector<ll>(W + 1, INF64));\n        vector<vector<short>> parPos(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parH(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n\n        for (int pos = 0; pos < N; pos++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[pos][used] >= INF64 / 4) continue;\n                for (int r = pos; r < N; r++) {\n                    int h = minH[pos][r];\n                    if (h == -1) break;\n                    int nu = used + h;\n                    if (nu > W) continue;\n                    ll cand = dp[pos][used] + quick_row_cost(pos, r, h) + rowPenalty;\n                    if (cand < dp[r + 1][nu]) {\n                        dp[r + 1][nu] = cand;\n                        parPos[r + 1][nu] = (short)pos;\n                        parH[r + 1][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        ll best = INF64;\n        int bestH = -1;\n        for (int h = 0; h <= W; h++) {\n            if (dp[N][h] < best) {\n                best = dp[N][h];\n                bestH = h;\n            }\n        }\n        if (bestH == -1) return {};\n\n        vector<pair<int,int>> rev;\n        int curPos = N, curH = bestH;\n        while (curPos > 0) {\n            int p = parPos[curPos][curH];\n            int ph = parH[curPos][curH];\n            if (p < 0 || ph < 0) return {};\n            rev.push_back({p, curPos - 1});\n            curPos = p;\n            curH = ph;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    ll score_partition_minheight(const vector<pair<int,int>>& parts) {\n        if (parts.empty()) return INF64;\n        int usedH = 0;\n        ll cost = 0;\n        for (auto [l, r] : parts) {\n            int h = minH[l][r];\n            if (h == -1) return INF64;\n            usedH += h;\n            if (usedH > W) return INF64;\n            cost += quick_row_cost(l, r, h);\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> improve_partition(vector<pair<int,int>> parts) {\n        ll cur = score_partition_minheight(parts);\n        if (cur >= INF64 / 4) return parts;\n\n        for (int round = 0; round < 15; round++) {\n            ll best = cur;\n            vector<pair<int,int>> bestParts = parts;\n            int G = (int)parts.size();\n\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n\n                if (l1 < r1) {\n                    auto np = parts;\n                    np[i] = {l1, r1 - 1};\n                    np[i + 1] = {r1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) best = sc, bestParts = np;\n                }\n\n                if (l2 < r2) {\n                    auto np = parts;\n                    np[i] = {l1, l2};\n                    np[i + 1] = {l2 + 1, r2};\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) best = sc, bestParts = np;\n                }\n            }\n\n            for (int i = 0; i + 1 < G; i++) {\n                auto [l1, r1] = parts[i];\n                auto [l2, r2] = parts[i + 1];\n                vector<pair<int,int>> np;\n                for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                np.push_back({l1, r2});\n                for (int j = i + 2; j < G; j++) np.push_back(parts[j]);\n                ll sc = score_partition_minheight(np);\n                if (sc < best) best = sc, bestParts = np;\n            }\n\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                if (l == r) continue;\n                for (int c = l; c < r; c++) {\n                    vector<pair<int,int>> np;\n                    for (int j = 0; j < i; j++) np.push_back(parts[j]);\n                    np.push_back({l, c});\n                    np.push_back({c + 1, r});\n                    for (int j = i + 1; j < G; j++) np.push_back(parts[j]);\n                    ll sc = score_partition_minheight(np);\n                    if (sc < best) best = sc, bestParts = np;\n                }\n            }\n\n            if (best >= cur) break;\n            cur = best;\n            parts = bestParts;\n        }\n        return parts;\n    }\n\n    pair<ll, vector<int>> allocate_heights_quick(const vector<pair<int,int>>& parts) {\n        int G = (int)parts.size();\n        if (G == 0) return {INF64, {}};\n\n        vector<int> hmin(G);\n        int used = 0;\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            hmin[i] = minH[l][r];\n            if (hmin[i] == -1) return {INF64, {}};\n            used += hmin[i];\n        }\n        if (used > W) return {INF64, {}};\n\n        int slack = W - used;\n\n        vector<vector<ll>> addCost(G, vector<ll>(slack + 1, INF64));\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            for (int e = 0; e <= slack; e++) {\n                addCost[i][e] = quick_row_cost(l, r, hmin[i] + e);\n            }\n        }\n\n        vector<vector<ll>> dp(G + 1, vector<ll>(slack + 1, INF64));\n        vector<vector<short>> par(G + 1, vector<short>(slack + 1, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < G; i++) {\n            for (int usedE = 0; usedE <= slack; usedE++) {\n                if (dp[i][usedE] >= INF64 / 4) continue;\n                for (int e = 0; usedE + e <= slack; e++) {\n                    ll cand = dp[i][usedE] + addCost[i][e];\n                    if (cand < dp[i + 1][usedE + e]) {\n                        dp[i + 1][usedE + e] = cand;\n                        par[i + 1][usedE + e] = (short)e;\n                    }\n                }\n            }\n        }\n\n        if (dp[G][slack] >= INF64 / 4) return {INF64, {}};\n\n        vector<int> heights(G);\n        int rem = slack;\n        for (int i = G; i >= 1; i--) {\n            int e = par[i][rem];\n            heights[i - 1] = hmin[i - 1] + e;\n            rem -= e;\n        }\n        return {dp[G][slack], heights};\n    }\n\n    ll eval_perm_cost_fast_last(const vector<vector<int>>& w, const vector<int>& perm, int h) const {\n        int m = (int)perm.size();\n        vector<vector<int>> cuts(D);\n\n        for (int d = 0; d < D; d++) {\n            int cur = 0;\n            cuts[d].reserve(max(0, m - 1));\n            for (int p = 0; p + 1 < m; p++) {\n                int t = perm[p];\n                cur += w[d][t];\n                cuts[d].push_back(cur);\n            }\n        }\n\n        ll v = 0;\n        for (int d = 1; d < D; d++) {\n            v += 1LL * h * symdiff_count_sorted(cuts[d - 1], cuts[d]);\n        }\n        return v;\n    }\n\n    pair<ll, vector<int>> optimize_slack_path(const vector<vector<int>>& w, const vector<int>& perm, int h) const {\n        int m = (int)perm.size();\n        if (m == 1) return {0LL, vector<int>(D, 0)};\n\n        vector<vector<vector<int>>> cuts(D, vector<vector<int>>(m));\n        for (int d = 0; d < D; d++) {\n            vector<int> bw(m);\n            int sumMin = 0;\n            for (int p = 0; p < m; p++) {\n                bw[p] = w[d][perm[p]];\n                sumMin += bw[p];\n            }\n            int slack = W - sumMin;\n\n            vector<int> pref(m - 1);\n            int cur = 0;\n            for (int p = 0; p + 1 < m; p++) {\n                cur += bw[p];\n                pref[p] = cur;\n            }\n\n            for (int q = 0; q < m; q++) {\n                cuts[d][q].resize(m - 1);\n                for (int p = 0; p + 1 < m; p++) {\n                    cuts[d][q][p] = pref[p] + (p >= q ? slack : 0);\n                }\n            }\n        }\n\n        vector<vector<ll>> dp(D, vector<ll>(m, INF64));\n        vector<vector<short>> par(D, vector<short>(m, -1));\n        for (int q = 0; q < m; q++) dp[0][q] = 0;\n\n        for (int d = 1; d < D; d++) {\n            for (int q2 = 0; q2 < m; q2++) {\n                ll best = INF64;\n                int bestq = -1;\n                for (int q1 = 0; q1 < m; q1++) {\n                    ll trans = 1LL * h * symdiff_count_sorted(cuts[d - 1][q1], cuts[d][q2]);\n                    ll cand = dp[d - 1][q1] + trans;\n                    if (cand < best) {\n                        best = cand;\n                        bestq = q1;\n                    }\n                }\n                dp[d][q2] = best;\n                par[d][q2] = (short)bestq;\n            }\n        }\n\n        ll best = INF64;\n        int endq = -1;\n        for (int q = 0; q < m; q++) {\n            if (dp[D - 1][q] < best) {\n                best = dp[D - 1][q];\n                endq = q;\n            }\n        }\n\n        vector<int> path(D);\n        path[D - 1] = endq;\n        for (int d = D - 1; d >= 1; d--) path[d - 1] = par[d][path[d]];\n        return {best, path};\n    }\n\n    RowSol build_row_sol(int l, int r, int h) const {\n        RowSol row;\n        row.l = l;\n        row.r = r;\n        row.h = h;\n        int m = r - l + 1;\n\n        vector<int> maxW(m, 0);\n        int sumMax = 0;\n        for (int t = 0; t < m; t++) {\n            int mx = 0;\n            for (int d = 0; d < D; d++) mx = max(mx, divup(a[d][l + t], h));\n            maxW[t] = mx;\n            sumMax += mx;\n        }\n\n        if (sumMax <= W) {\n            row.isConst = true;\n            row.perm.resize(m);\n            iota(row.perm.begin(), row.perm.end(), 0);\n            row.constWPos = maxW;\n            row.constWPos.back() += W - sumMax;\n            row.vcost = 0;\n            return row;\n        }\n\n        row.isConst = false;\n        row.w.assign(D, vector<int>(m));\n        for (int d = 0; d < D; d++) {\n            for (int t = 0; t < m; t++) {\n                row.w[d][t] = divup(a[d][l + t], h);\n            }\n        }\n\n        vector<int> vol(m, 0), avgw(m, 0);\n        for (int t = 0; t < m; t++) {\n            for (int d = 1; d < D; d++) vol[t] += abs(row.w[d][t] - row.w[d - 1][t]);\n            for (int d = 0; d < D; d++) avgw[t] += row.w[d][t];\n        }\n\n        vector<vector<int>> init_orders;\n        auto add_unique = [&](const vector<int>& ord) {\n            for (auto& v : init_orders) if (v == ord) return;\n            init_orders.push_back(ord);\n        };\n\n        vector<int> id(m), rev(m), byVol(m), byAvg(m);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        byVol = id;\n        sort(byVol.begin(), byVol.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            return x < y;\n        });\n\n        byAvg = id;\n        sort(byAvg.begin(), byAvg.end(), [&](int x, int y) {\n            if (avgw[x] != avgw[y]) return avgw[x] < avgw[y];\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            return x < y;\n        });\n\n        add_unique(id);\n        add_unique(rev);\n        add_unique(byVol);\n        reverse(byVol.begin(), byVol.end());\n        add_unique(byVol);\n        add_unique(byAvg);\n        reverse(byAvg.begin(), byAvg.end());\n        add_unique(byAvg);\n\n        ll bestCost = INF64;\n        vector<int> bestPerm = id, bestQ(D, 0);\n\n        auto improve = [&](vector<int> perm) -> vector<int> {\n            ll cur = eval_perm_cost_fast_last(row.w, perm, h);\n\n            for (int round = 0; round < 5; round++) {\n                ll best = cur;\n                int bi = -1, bj = -1;\n                for (int i = 0; i < m; i++) {\n                    for (int j = i + 1; j < m; j++) {\n                        swap(perm[i], perm[j]);\n                        ll sc = eval_perm_cost_fast_last(row.w, perm, h);\n                        swap(perm[i], perm[j]);\n                        if (sc < best) {\n                            best = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(perm[bi], perm[bj]);\n                cur = best;\n            }\n\n            for (int round = 0; round < 2; round++) {\n                ll best = cur;\n                vector<int> bestP = perm;\n                for (int i = 0; i < m; i++) {\n                    for (int j = 0; j < m; j++) if (i != j) {\n                        vector<int> np = perm;\n                        int v = np[i];\n                        np.erase(np.begin() + i);\n                        np.insert(np.begin() + j, v);\n                        ll sc = eval_perm_cost_fast_last(row.w, np, h);\n                        if (sc < best) {\n                            best = sc;\n                            bestP = np;\n                        }\n                    }\n                }\n                if (best >= cur) break;\n                cur = best;\n                perm = bestP;\n            }\n\n            return perm;\n        };\n\n        for (auto ord : init_orders) {\n            auto p = improve(ord);\n            auto [cost, qPath] = optimize_slack_path(row.w, p, h);\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestPerm = p;\n                bestQ = qPath;\n            }\n        }\n\n        row.perm = bestPerm;\n        row.qPath = bestQ;\n        row.vcost = bestCost;\n        return row;\n    }\n\n    const RowSol& get_row_sol(int l, int r, int h) {\n        long long key = row_key(l, r, h);\n        auto it = rowCacheId.find(key);\n        if (it != rowCacheId.end()) return rowCache[it->second];\n        int idx = (int)rowCache.size();\n        rowCacheId[key] = idx;\n        rowCache.push_back(build_row_sol(l, r, h));\n        return rowCache[idx];\n    }\n\n    pair<ll, vector<int>> improve_heights_exact(const vector<pair<int,int>>& parts, vector<int> heights) {\n        int G = (int)parts.size();\n        if (G == 0) return {INF64, heights};\n\n        vector<int> hmin(G);\n        vector<ll> rowCost(G, 0);\n        ll cur = 0;\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            hmin[i] = minH[l][r];\n            rowCost[i] = get_row_sol(l, r, heights[i]).vcost;\n            cur += rowCost[i];\n        }\n\n        if (G > 12) return {cur, heights};\n\n        static const int DELTAS[] = {1, 2, 4, 8, 16, 32};\n\n        for (int round = 0; round < 3; round++) {\n            ll best = cur;\n            int bi = -1, bj = -1, bd = -1;\n            ll nci = 0, ncj = 0;\n\n            for (int i = 0; i < G; i++) {\n                auto [li, ri] = parts[i];\n                for (int dlt : DELTAS) {\n                    if (heights[i] - dlt < hmin[i]) continue;\n                    ll ci2 = get_row_sol(li, ri, heights[i] - dlt).vcost;\n                    for (int j = 0; j < G; j++) if (i != j) {\n                        auto [lj, rj] = parts[j];\n                        ll cj2 = get_row_sol(lj, rj, heights[j] + dlt).vcost;\n                        ll cand = cur - rowCost[i] - rowCost[j] + ci2 + cj2;\n                        if (cand < best) {\n                            best = cand;\n                            bi = i;\n                            bj = j;\n                            bd = dlt;\n                            nci = ci2;\n                            ncj = cj2;\n                        }\n                    }\n                }\n            }\n\n            if (bi == -1) break;\n            heights[bi] -= bd;\n            heights[bj] += bd;\n            rowCost[bi] = nci;\n            rowCost[bj] = ncj;\n            cur = best;\n        }\n\n        return {cur, heights};\n    }\n\n    pair<ll, vector<int>> exact_height_dp(const vector<pair<int,int>>& parts) {\n        int G = (int)parts.size();\n        if (G == 0) return {INF64, {}};\n\n        vector<int> hmin(G);\n        int base = 0;\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            hmin[i] = minH[l][r];\n            if (hmin[i] == -1) return {INF64, {}};\n            base += hmin[i];\n        }\n        if (base > W) return {INF64, {}};\n\n        int slack = W - base;\n        vector<vector<ll>> cost(G, vector<ll>(slack + 1, INF64));\n        for (int i = 0; i < G; i++) {\n            auto [l, r] = parts[i];\n            for (int e = 0; e <= slack; e++) {\n                cost[i][e] = get_row_sol(l, r, hmin[i] + e).vcost;\n            }\n        }\n\n        vector<vector<ll>> dp(G + 1, vector<ll>(slack + 1, INF64));\n        vector<vector<short>> par(G + 1, vector<short>(slack + 1, -1));\n        dp[0][0] = 0;\n\n        for (int i = 0; i < G; i++) {\n            for (int used = 0; used <= slack; used++) {\n                if (dp[i][used] >= INF64 / 4) continue;\n                for (int e = 0; used + e <= slack; e++) {\n                    ll cand = dp[i][used] + cost[i][e];\n                    if (cand < dp[i + 1][used + e]) {\n                        dp[i + 1][used + e] = cand;\n                        par[i + 1][used + e] = (short)e;\n                    }\n                }\n            }\n        }\n\n        if (dp[G][slack] >= INF64 / 4) return {INF64, {}};\n\n        vector<int> heights(G);\n        int rem = slack;\n        for (int i = G; i >= 1; i--) {\n            int e = par[i][rem];\n            heights[i - 1] = hmin[i - 1] + e;\n            rem -= e;\n        }\n        return {dp[G][slack], heights};\n    }\n\n    Candidate solve_shelf_candidate() {\n        precompute_min_heights();\n\n        vector<vector<pair<int,int>>> candParts;\n        auto add_parts = [&](vector<pair<int,int>> p) {\n            if (p.empty()) return;\n            for (auto& q : candParts) if (q == p) return;\n            candParts.push_back(p);\n        };\n\n        vector<int> penalties = {0, 80, 200, 500, 1200, 3000, 10000};\n        for (int pen : penalties) {\n            auto p = partition_dp(pen);\n            if (p.empty()) continue;\n            p = improve_partition(p);\n            add_parts(p);\n        }\n\n        if (minH[0][N - 1] != -1) {\n            vector<pair<int,int>> p = {{0, N - 1}};\n            p = improve_partition(p);\n            add_parts(p);\n        }\n\n        {\n            int sum = 0;\n            bool ok = true;\n            vector<pair<int,int>> p;\n            for (int k = 0; k < N; k++) {\n                if (minH[k][k] == -1) ok = false;\n                else sum += minH[k][k];\n                p.push_back({k, k});\n            }\n            if (ok && sum <= W) add_parts(p);\n        }\n\n        vector<Seed> seeds;\n        for (auto& parts : candParts) {\n            auto [proxy, heights] = allocate_heights_quick(parts);\n            if (proxy >= INF64 / 4) continue;\n            seeds.push_back({parts, heights, proxy});\n        }\n\n        sort(seeds.begin(), seeds.end(), [&](const Seed& x, const Seed& y) {\n            return x.proxy < y.proxy;\n        });\n\n        Candidate best;\n        int shortlist = min<int>((int)seeds.size(), 8);\n        int exactDpTop = min<int>((int)seeds.size(), 3);\n\n        for (int si = 0; si < (int)seeds.size(); si++) {\n            auto parts = seeds[si].parts;\n            auto heights = seeds[si].heights;\n\n            ll exactCost;\n            if (si < exactDpTop && (int)parts.size() <= 12) {\n                auto improved = exact_height_dp(parts);\n                exactCost = improved.first;\n                heights = improved.second;\n            } else if (si < shortlist) {\n                auto improved = improve_heights_exact(parts, heights);\n                exactCost = improved.first;\n                heights = improved.second;\n            } else {\n                exactCost = 0;\n                for (int i = 0; i < (int)parts.size(); i++) {\n                    auto [l, r] = parts[i];\n                    exactCost += get_row_sol(l, r, heights[i]).vcost;\n                }\n            }\n\n            if (exactCost >= best.cost) continue;\n\n            int G = (int)parts.size();\n            vector<RowSol> rows;\n            rows.reserve(G);\n            bool ok = true;\n\n            for (int i = 0; i < G; i++) {\n                auto [l, r] = parts[i];\n                int h = heights[i];\n                if (!feasible_seg(l, r, h)) {\n                    ok = false;\n                    break;\n                }\n                rows.push_back(get_row_sol(l, r, h));\n            }\n            if (!ok) continue;\n\n            vector<vector<Rect>> ans(D, vector<Rect>(N));\n            int y = 0;\n            for (int i = 0; i < G; i++) {\n                const RowSol& row = rows[i];\n                int m = row.r - row.l + 1;\n                int y0 = y, y1 = y + row.h;\n                y = y1;\n\n                if (row.isConst) {\n                    for (int d = 0; d < D; d++) {\n                        int x = 0;\n                        for (int p = 0; p < m; p++) {\n                            int t = row.perm[p];\n                            int k = row.l + t;\n                            int ww = row.constWPos[p];\n                            ans[d][k] = {y0, x, y1, x + ww};\n                            x += ww;\n                        }\n                        if (x != W) ok = false;\n                    }\n                } else {\n                    for (int d = 0; d < D; d++) {\n                        int sumMin = 0;\n                        for (int t = 0; t < m; t++) sumMin += row.w[d][t];\n                        int slackW = W - sumMin;\n                        int q = row.qPath[d];\n\n                        int x = 0;\n                        for (int p = 0; p < m; p++) {\n                            int t = row.perm[p];\n                            int k = row.l + t;\n                            int ww = row.w[d][t] + (p == q ? slackW : 0);\n                            ans[d][k] = {y0, x, y1, x + ww};\n                            x += ww;\n                        }\n                        if (x != W) ok = false;\n                    }\n                }\n            }\n            if (!ok || y != W) continue;\n\n            best.ans = std::move(ans);\n            best.cost = exactCost;\n        }\n\n        return best;\n    }\n\n    // ---------- exact analytical strip candidate ----------\n\n    static ll shortage_cost_day_profile(const vector<int>& demand, const vector<int>& prof_sorted, int W) {\n        ll s = 0;\n        for (int k = 0; k < (int)demand.size(); k++) {\n            ll area = 1LL * W * prof_sorted[k];\n            if (area < demand[k]) s += demand[k] - area;\n        }\n        return 100LL * s;\n    }\n\n    pair<vector<int>, int> make_local_profile(int d) const {\n        vector<int> c(N, 1);\n        int rem = W - N;\n\n        while (rem > 0) {\n            int bestGain = 0, bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int deficit = a[d][k] - W * c[k];\n                int gain = deficit > 0 ? min(W, deficit) : 0;\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    pair<vector<int>, int> make_global_profile() const {\n        vector<int> c(N, 1);\n        int rem = W - N;\n\n        while (rem > 0) {\n            int bestGain = 0, bestK = -1;\n            for (int k = 0; k < N; k++) {\n                if (k + 1 < N && c[k] + 1 > c[k + 1]) continue;\n                int gain = 0;\n                for (int d = 0; d < D; d++) {\n                    int deficit = a[d][k] - W * c[k];\n                    if (deficit > 0) gain += min(W, deficit);\n                }\n                if (gain > bestGain || (gain == bestGain && gain > 0 && k > bestK)) {\n                    bestGain = gain;\n                    bestK = k;\n                }\n            }\n            if (bestGain <= 0) break;\n            c[bestK]++;\n            rem--;\n        }\n        return {c, rem};\n    }\n\n    ll trans_cost_pref(const int* p1, const int* p2) const {\n        int len = N - 1;\n        int i = 0, j = 0, common = 0;\n        while (i < len && j < len) {\n            if (p1[i] == p2[j]) {\n                common++;\n                i++;\n                j++;\n            } else if (p1[i] < p2[j]) {\n                i++;\n            } else {\n                j++;\n            }\n        }\n        return 2LL * W * (len - common);\n    }\n\n    ll eval_perm_strip(\n        const vector<int>& perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        ll dpL = locShort[0];\n        ll dpG = globShort[0];\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            ll ndpL = min(dpL + llc, dpG + glc) + locShort[d];\n            ll ndpG = min(dpL + lgc, dpG) + globShort[d];\n\n            dpL = ndpL;\n            dpG = ndpG;\n        }\n        return min(dpL, dpG);\n    }\n\n    vector<int> descend_perm_strip(\n        vector<int> perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        ll cur = eval_perm_strip(perm, locProf, locShort, globProf, globShort);\n        for (int round = 0; round < 20; round++) {\n            ll best = cur;\n            int bi = -1, bj = -1;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    swap(perm[i], perm[j]);\n                    ll sc = eval_perm_strip(perm, locProf, locShort, globProf, globShort);\n                    swap(perm[i], perm[j]);\n                    if (sc < best) {\n                        best = sc;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n            if (bi == -1) break;\n            swap(perm[bi], perm[bj]);\n            cur = best;\n        }\n        return perm;\n    }\n\n    vector<int> choose_best_perm_strip(\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        vector<ll> vol(N, 0), avg(N, 0);\n        for (int k = 0; k < N; k++) {\n            for (int d = 1; d < D; d++) vol[k] += llabs(locProf[d][k] - locProf[d - 1][k]);\n            for (int d = 0; d < D; d++) avg[k] += locProf[d][k];\n        }\n\n        vector<int> id(N), rev(N), v1(N), v2(N);\n        iota(id.begin(), id.end(), 0);\n        rev = id;\n        reverse(rev.begin(), rev.end());\n\n        iota(v1.begin(), v1.end(), 0);\n        sort(v1.begin(), v1.end(), [&](int x, int y) {\n            if (vol[x] != vol[y]) return vol[x] < vol[y];\n            if (avg[x] != avg[y]) return avg[x] < avg[y];\n            return x < y;\n        });\n\n        v2 = v1;\n        reverse(v2.begin(), v2.end());\n\n        vector<vector<int>> uniq;\n        auto add = [&](const vector<int>& p) {\n            for (auto& q : uniq) if (q == p) return;\n            uniq.push_back(p);\n        };\n        add(id);\n        add(rev);\n        add(v1);\n        add(v2);\n\n        vector<int> bestPerm = uniq[0];\n        ll bestScore = INF64;\n\n        for (auto p : uniq) {\n            p = descend_perm_strip(p, locProf, locShort, globProf, globShort);\n            ll sc = eval_perm_strip(p, locProf, locShort, globProf, globShort);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestPerm = p;\n            }\n        }\n\n        return descend_perm_strip(bestPerm, locProf, locShort, globProf, globShort);\n    }\n\n    vector<int> reconstruct_states_strip(\n        const vector<int>& perm,\n        const vector<vector<int>>& locProf,\n        const vector<ll>& locShort,\n        const vector<int>& globProf,\n        const vector<ll>& globShort\n    ) const {\n        static int prefLoc[55][55];\n        static int prefGlob[55];\n\n        for (int d = 0; d < D; d++) {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += locProf[d][perm[t]];\n                prefLoc[d][t] = s;\n            }\n        }\n        {\n            int s = 0;\n            for (int t = 0; t < N - 1; t++) {\n                s += globProf[perm[t]];\n                prefGlob[t] = s;\n            }\n        }\n\n        vector<array<ll, 2>> dp(D);\n        vector<array<int, 2>> par(D);\n\n        dp[0][0] = locShort[0];\n        dp[0][1] = globShort[0];\n        par[0][0] = par[0][1] = -1;\n\n        for (int d = 1; d < D; d++) {\n            ll llc = trans_cost_pref(prefLoc[d - 1], prefLoc[d]);\n            ll lgc = trans_cost_pref(prefLoc[d - 1], prefGlob);\n            ll glc = trans_cost_pref(prefGlob, prefLoc[d]);\n\n            ll a0 = dp[d - 1][0] + llc;\n            ll a1 = dp[d - 1][1] + glc;\n            if (a0 <= a1) {\n                dp[d][0] = a0 + locShort[d];\n                par[d][0] = 0;\n            } else {\n                dp[d][0] = a1 + locShort[d];\n                par[d][0] = 1;\n            }\n\n            a0 = dp[d - 1][0] + lgc;\n            a1 = dp[d - 1][1];\n            if (a0 <= a1) {\n                dp[d][1] = a0 + globShort[d];\n                par[d][1] = 0;\n            } else {\n                dp[d][1] = a1 + globShort[d];\n                par[d][1] = 1;\n            }\n        }\n\n        vector<int> state(D);\n        state[D - 1] = (dp[D - 1][0] <= dp[D - 1][1] ? 0 : 1);\n        for (int d = D - 1; d >= 1; d--) state[d - 1] = par[d][state[d]];\n        return state;\n    }\n\n    Candidate solve_strip_candidate() const {\n        vector<vector<int>> locProf(D, vector<int>(N));\n        vector<int> locRem(D, 0);\n        vector<ll> locShort(D, 0);\n\n        for (int d = 0; d < D; d++) {\n            auto [c, rem] = make_local_profile(d);\n            locProf[d] = c;\n            locRem[d] = rem;\n            locShort[d] = shortage_cost_day_profile(a[d], c, W);\n        }\n\n        auto [globProf, globRem] = make_global_profile();\n        vector<ll> globShort(D, 0);\n        for (int d = 0; d < D; d++) {\n            globShort[d] = shortage_cost_day_profile(a[d], globProf, W);\n        }\n\n        vector<int> perm = choose_best_perm_strip(locProf, locShort, globProf, globShort);\n        ll exactCost = eval_perm_strip(perm, locProf, locShort, globProf, globShort);\n        vector<int> state = reconstruct_states_strip(perm, locProf, locShort, globProf, globShort);\n\n        Candidate cand;\n        cand.cost = exactCost;\n        cand.ans.assign(D, vector<Rect>(N));\n\n        for (int d = 0; d < D; d++) {\n            vector<int> x(N);\n            if (state[d] == 0) {\n                for (int i = 0; i < N; i++) x[i] = locProf[d][perm[i]];\n                x[N - 1] += locRem[d];\n            } else {\n                for (int i = 0; i < N; i++) x[i] = globProf[perm[i]];\n                x[N - 1] += globRem;\n            }\n\n            vector<int> top(N), bot(N);\n            int cur = 0;\n            for (int i = 0; i < N; i++) {\n                top[i] = cur;\n                cur += x[i];\n                bot[i] = cur;\n            }\n            if (cur != W) bot[N - 1] += W - cur;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            stable_sort(ord.begin(), ord.end(), [&](int x1, int x2) {\n                if (x[x1] != x[x2]) return x[x1] < x[x2];\n                return x1 < x2;\n            });\n\n            for (int k = 0; k < N; k++) {\n                int idx = ord[k];\n                cand.ans[d][k] = {top[idx], 0, bot[idx], W};\n            }\n        }\n\n        return cand;\n    }\n\n    bool validate_answer(const vector<vector<Rect>>& ans) const {\n        if ((int)ans.size() != D) return false;\n        for (int d = 0; d < D; d++) {\n            if ((int)ans[d].size() != N) return false;\n            for (int k = 0; k < N; k++) {\n                const auto& r = ans[d][k];\n                if (!(0 <= r.i0 && r.i0 < r.i1 && r.i1 <= W)) return false;\n                if (!(0 <= r.j0 && r.j0 < r.j1 && r.j1 <= W)) return false;\n            }\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    const auto& A = ans[d][i];\n                    const auto& B = ans[d][j];\n                    int h = min(A.i1, B.i1) - max(A.i0, B.i0);\n                    int w = min(A.j1, B.j1) - max(A.j0, B.j0);\n                    if (h > 0 && w > 0) return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    vector<vector<Rect>> fallback_answer() const {\n        vector<vector<Rect>> ans(D, vector<Rect>(N));\n        for (int d = 0; d < D; d++) {\n            for (int k = 0; k < N; k++) {\n                ans[d][k] = {k, 0, k + 1, W};\n            }\n        }\n        return ans;\n    }\n\n    void solve() {\n        Candidate best;\n\n        {\n            Candidate cand = solve_shelf_candidate();\n            if (!cand.ans.empty()) best = cand;\n        }\n\n        {\n            Candidate cand = solve_strip_candidate();\n            if (!cand.ans.empty() && cand.cost < best.cost) best = cand;\n        }\n\n        vector<vector<Rect>> ans;\n        if (!best.ans.empty()) ans = best.ans;\n        else ans = fallback_answer();\n\n        if (!validate_answer(ans)) ans = fallback_answer();\n\n        for (int d = 0; d < D; d++) {\n            for (int k = 0; k < N; k++) {\n                const auto& r = ans[d][k];\n                cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 9;\nstatic constexpr int POS = 7;\nstatic constexpr int CELL = 81;\nstatic constexpr int MOD = 998244353;\nstatic constexpr int MAX_A = 20 * 7 * 7; // 980\nstatic constexpr int ELITE_CAP = 4;\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 Action {\n    int m, p, q;\n    array<uint8_t, 9> cell;\n    array<int, 9> val;\n};\n\nstruct Solution {\n    array<int, CELL> r{};\n    array<uint8_t, MAX_A> cnt{};\n    array<long long, MAX_A> add_gain{};\n    vector<uint16_t> ops;\n    int L = 0;\n    long long score = 0;\n};\n\nstruct BestAdd {\n    long long gain = 0;\n    int id = -1;\n};\nstruct BestRemove {\n    long long gain = 0;\n    int id = -1;\n};\nstruct BestPair {\n    long long gain = 0;\n    int a = -1, b = -1;\n};\nstruct BestSwap {\n    long long gain = 0;\n    int rem = -1, add = -1;\n};\nstruct BestExpand12 {\n    long long gain = 0;\n    int rem = -1, a = -1, b = -1;\n};\n\nstruct ImproveParam {\n    int top_pair;\n    int top_swap;\n    int exp_top_rem;\n    int exp_top_add;\n    int rounds;\n};\n\nint M_in, K_in;\narray<int, CELL> init_r;\nvector<Action> actions;\narray<vector<int>, CELL> cell_to_actions;\nint A = 0;\n\narray<int, MAX_A> seen_action{};\nint seen_token = 1;\n\ninline bool action_touches_cell(int aid, int c) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        if (ac.cell[k] == c) return true;\n    }\n    return false;\n}\n\ninline long long calc_add_gain_board(const array<int, CELL>& r, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int v = ac.val[k];\n        delta += (r[idx] + v >= MOD ? (long long)v - MOD : (long long)v);\n    }\n    return delta;\n}\n\ninline long long gain_add(const Solution& s, int aid) {\n    return s.add_gain[aid];\n}\n\ninline long long gain_remove(const Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int v = ac.val[k];\n        delta += (s.r[idx] < v ? (long long)MOD - v : -(long long)v);\n    }\n    return delta;\n}\n\ninline long long gain_swap(const Solution& s, int rem_id, int add_id) {\n    if (rem_id == add_id) return 0;\n    const auto& rm = actions[rem_id];\n    const auto& ad = actions[add_id];\n\n    long long delta = 0;\n    bool used_ad[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = rm.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv - rm.val[i];\n        if (nv < 0) nv += MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (ad.cell[j] == idx) {\n                nv += ad.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_ad[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_ad[j]) {\n            int idx = ad.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + ad.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline long long gain_add_pair(const Solution& s, int a_id, int b_id) {\n    const auto& a = actions[a_id];\n    const auto& b = actions[b_id];\n\n    long long delta = 0;\n    bool used_b[9] = {};\n\n    for (int i = 0; i < 9; ++i) {\n        int idx = a.cell[i];\n        int oldv = s.r[idx];\n        int nv = oldv + a.val[i];\n        if (nv >= MOD) nv -= MOD;\n\n        for (int j = 0; j < 9; ++j) {\n            if (b.cell[j] == idx) {\n                nv += b.val[j];\n                if (nv >= MOD) nv -= MOD;\n                used_b[j] = true;\n                break;\n            }\n        }\n        delta += (long long)nv - oldv;\n    }\n\n    for (int j = 0; j < 9; ++j) {\n        if (!used_b[j]) {\n            int idx = b.cell[j];\n            int oldv = s.r[idx];\n            int nv = oldv + b.val[j];\n            if (nv >= MOD) nv -= MOD;\n            delta += (long long)nv - oldv;\n        }\n    }\n    return delta;\n}\n\ninline void refresh_affected_by_action(Solution& s, int acted_aid) {\n    if (++seen_token == INT_MAX) {\n        seen_action.fill(0);\n        seen_token = 1;\n    }\n    const auto& ac = actions[acted_aid];\n    for (int k = 0; k < 9; ++k) {\n        int c = ac.cell[k];\n        for (int aid : cell_to_actions[c]) {\n            if (seen_action[aid] == seen_token) continue;\n            seen_action[aid] = seen_token;\n            s.add_gain[aid] = calc_add_gain_board(s.r, aid);\n        }\n    }\n}\n\ninline void apply_add(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv + ac.val[k];\n        if (nv >= MOD) nv -= MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    ++s.cnt[aid];\n    s.ops.push_back((uint16_t)aid);\n    ++s.L;\n    refresh_affected_by_action(s, aid);\n}\n\ninline void apply_remove_aid(Solution& s, int aid) {\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n    for (int i = (int)s.ops.size() - 1; i >= 0; --i) {\n        if ((int)s.ops[i] == aid) {\n            s.ops[i] = s.ops.back();\n            s.ops.pop_back();\n            break;\n        }\n    }\n    refresh_affected_by_action(s, aid);\n}\n\ninline void apply_remove_index(Solution& s, int idx_in_ops) {\n    int aid = s.ops[idx_in_ops];\n    const auto& ac = actions[aid];\n    for (int k = 0; k < 9; ++k) {\n        int idx = ac.cell[k];\n        int oldv = s.r[idx];\n        int nv = oldv - ac.val[k];\n        if (nv < 0) nv += MOD;\n        s.r[idx] = nv;\n        s.score += (long long)nv - oldv;\n    }\n    --s.cnt[aid];\n    --s.L;\n    s.ops[idx_in_ops] = s.ops.back();\n    s.ops.pop_back();\n    refresh_affected_by_action(s, aid);\n}\n\nvoid init_all_add_gains(Solution& s) {\n    for (int aid = 0; aid < A; ++aid) {\n        s.add_gain[aid] = calc_add_gain_board(s.r, aid);\n    }\n}\n\nSolution make_base_solution() {\n    Solution s;\n    s.r = init_r;\n    s.cnt.fill(0);\n    s.ops.clear();\n    s.ops.reserve(K_in);\n    s.L = 0;\n    s.score = 0;\n    for (int i = 0; i < CELL; ++i) s.score += s.r[i];\n    init_all_add_gains(s);\n    return s;\n}\n\nBestAdd best_single_add(const Solution& s) {\n    BestAdd res;\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = s.add_gain[aid];\n        if (g > res.gain) {\n            res.gain = g;\n            res.id = aid;\n        }\n    }\n    return res;\n}\n\nBestRemove best_single_remove(const Solution& s) {\n    BestRemove res;\n    for (int aid = 0; aid < A; ++aid) {\n        if (!s.cnt[aid]) continue;\n        long long g = gain_remove(s, aid);\n        if (g > res.gain) {\n            res.gain = g;\n            res.id = aid;\n        }\n    }\n    return res;\n}\n\nvector<pair<long long, int>> top_adds(const Solution& s, int T, bool positive_only = false) {\n    vector<pair<long long, int>> v;\n    v.reserve(A);\n    for (int aid = 0; aid < A; ++aid) {\n        long long g = s.add_gain[aid];\n        if (!positive_only || g > 0) v.push_back({g, aid});\n    }\n    if (v.empty()) return v;\n    if ((int)v.size() > T) {\n        nth_element(v.begin(), v.begin() + T, v.end(),\n                    [](const auto& x, const auto& y) { return x.first > y.first; });\n        v.resize(T);\n    }\n    sort(v.begin(), v.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    return v;\n}\n\nBestPair best_pair_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestPair res;\n    int T = (int)cand.size();\n    for (int i = 0; i < T; ++i) {\n        int a = cand[i].second;\n        for (int j = i; j < T; ++j) {\n            int b = cand[j].second;\n            long long g = gain_add_pair(s, a, b);\n            if (g > res.gain) {\n                res.gain = g;\n                res.a = a;\n                res.b = b;\n            }\n        }\n    }\n    return res;\n}\n\nBestSwap best_swap_from_candidates(const Solution& s, const vector<pair<long long, int>>& cand) {\n    BestSwap res;\n    if (s.L == 0) return res;\n\n    vector<int> used_ids;\n    used_ids.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (s.cnt[aid]) used_ids.push_back(aid);\n    }\n\n    for (int rem : used_ids) {\n        for (auto [dummy_gain, add] : cand) {\n            (void)dummy_gain;\n            if (add == rem) continue;\n            long long g = gain_swap(s, rem, add);\n            if (g > res.gain) {\n                res.gain = g;\n                res.rem = rem;\n                res.add = add;\n            }\n        }\n    }\n    return res;\n}\n\nBestSwap best_swap_all(const Solution& s, const Timer& timer, double deadline) {\n    BestSwap res;\n    if (s.L == 0) return res;\n\n    vector<int> used_ids;\n    used_ids.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (s.cnt[aid]) used_ids.push_back(aid);\n    }\n\n    int outer = 0;\n    for (int rem : used_ids) {\n        for (int add = 0; add < A; ++add) {\n            if (add == rem) continue;\n            long long g = gain_swap(s, rem, add);\n            if (g > res.gain) {\n                res.gain = g;\n                res.rem = rem;\n                res.add = add;\n            }\n        }\n        if ((++outer & 7) == 0 && timer.elapsed() >= deadline) break;\n    }\n    return res;\n}\n\nBestExpand12 best_expand_1_to_2(const Solution& s, int top_rem, int top_add) {\n    BestExpand12 res;\n    if (s.L == 0 || s.L > K_in - 1) return res;\n\n    vector<pair<long long, int>> rems;\n    rems.reserve(s.L);\n    for (int aid = 0; aid < A; ++aid) {\n        if (!s.cnt[aid]) continue;\n        rems.push_back({gain_remove(s, aid), aid});\n    }\n    sort(rems.begin(), rems.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    if ((int)rems.size() > top_rem) rems.resize(top_rem);\n\n    for (auto [gr, rem] : rems) {\n        Solution t = s;\n        apply_remove_aid(t, rem);\n        auto cand = top_adds(t, top_add, false);\n        auto bp = best_pair_from_candidates(t, cand);\n        long long g = gr + bp.gain;\n        if (g > res.gain) {\n            res.gain = g;\n            res.rem = rem;\n            res.a = bp.a;\n            res.b = bp.b;\n        }\n    }\n    return res;\n}\n\ntemplate <class RNG>\nvoid randomized_fill(Solution& s, RNG& rng, int topT = 18) {\n    while (s.L < K_in) {\n        auto cand = top_adds(s, topT, true);\n        if (cand.empty() || cand[0].first <= 0) break;\n\n        int t = min<int>(8, cand.size());\n        int total_w = t * (t + 1) / 2;\n        int r = (int)(rng() % total_w);\n        int acc = 0;\n        int pick = cand[0].second;\n        for (int i = 0; i < t; ++i) {\n            acc += (t - i);\n            if (r < acc) {\n                pick = cand[i].second;\n                break;\n            }\n        }\n        apply_add(s, pick);\n    }\n}\n\ntemplate <class RNG>\nSolution build_greedy(bool randomized, RNG& rng) {\n    Solution s = make_base_solution();\n    if (!randomized) {\n        while (s.L < K_in) {\n            auto ba = best_single_add(s);\n            if (ba.gain <= 0) break;\n            apply_add(s, ba.id);\n        }\n    } else {\n        randomized_fill(s, rng, 18);\n    }\n    return s;\n}\n\nvoid local_improve(Solution& s, const Timer& timer, double deadline, const ImproveParam& prm) {\n    for (int round = 0; round < prm.rounds && timer.elapsed() < deadline; ++round) {\n        bool changed = false;\n\n        while (s.L < K_in && timer.elapsed() < deadline) {\n            auto ba = best_single_add(s);\n            if (ba.gain <= 0) break;\n            apply_add(s, ba.id);\n            changed = true;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        long long best_gain = 0;\n        int best_type = 0; // 1 remove, 2 swap, 3 pair, 4 expand\n        int x = -1, y = -1, z = -1;\n\n        auto br = best_single_remove(s);\n        if (br.gain > best_gain) {\n            best_gain = br.gain;\n            best_type = 1;\n            x = br.id;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        auto cand_swap = top_adds(s, prm.top_swap, false);\n\n        if (s.L > 0) {\n            auto bs = best_swap_from_candidates(s, cand_swap);\n            if (bs.gain > best_gain) {\n                best_gain = bs.gain;\n                best_type = 2;\n                x = bs.rem;\n                y = bs.add;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 2) {\n            vector<pair<long long, int>> cand_pair;\n            int take = min<int>(prm.top_pair, cand_swap.size());\n            cand_pair.assign(cand_swap.begin(), cand_swap.begin() + take);\n            auto bp = best_pair_from_candidates(s, cand_pair);\n            if (bp.gain > best_gain) {\n                best_gain = bp.gain;\n                best_type = 3;\n                x = bp.a;\n                y = bp.b;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 1 && s.L > 0) {\n            auto be = best_expand_1_to_2(s, prm.exp_top_rem, prm.exp_top_add);\n            if (be.gain > best_gain) {\n                best_gain = be.gain;\n                best_type = 4;\n                x = be.rem;\n                y = be.a;\n                z = be.b;\n            }\n        }\n\n        if (best_gain <= 0) {\n            if (!changed) break;\n            continue;\n        }\n\n        if (best_type == 1) {\n            apply_remove_aid(s, x);\n        } else if (best_type == 2) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n        } else if (best_type == 3) {\n            apply_add(s, x);\n            apply_add(s, y);\n        } else if (best_type == 4) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n            apply_add(s, z);\n        }\n    }\n}\n\nvoid final_exact_polish(Solution& s, const Timer& timer, double deadline) {\n    const int TOP_PAIR = 180;\n    const int EXP_TOP_REM = 6;\n    const int EXP_TOP_ADD = 80;\n\n    for (int round = 0; round < 3 && timer.elapsed() < deadline; ++round) {\n        bool changed = false;\n\n        while (s.L < K_in && timer.elapsed() < deadline) {\n            auto ba = best_single_add(s);\n            if (ba.gain <= 0) break;\n            apply_add(s, ba.id);\n            changed = true;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        long long best_gain = 0;\n        int best_type = 0; // 1 remove, 2 exact swap, 3 pair, 4 expand\n        int x = -1, y = -1, z = -1;\n\n        auto br = best_single_remove(s);\n        if (br.gain > best_gain) {\n            best_gain = br.gain;\n            best_type = 1;\n            x = br.id;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        auto bs = best_swap_all(s, timer, deadline);\n        if (bs.gain > best_gain) {\n            best_gain = bs.gain;\n            best_type = 2;\n            x = bs.rem;\n            y = bs.add;\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 2) {\n            auto cand = top_adds(s, TOP_PAIR, false);\n            auto bp = best_pair_from_candidates(s, cand);\n            if (bp.gain > best_gain) {\n                best_gain = bp.gain;\n                best_type = 3;\n                x = bp.a;\n                y = bp.b;\n            }\n        }\n        if (timer.elapsed() >= deadline) break;\n\n        if (s.L <= K_in - 1 && s.L > 0) {\n            auto be = best_expand_1_to_2(s, EXP_TOP_REM, EXP_TOP_ADD);\n            if (be.gain > best_gain) {\n                best_gain = be.gain;\n                best_type = 4;\n                x = be.rem;\n                y = be.a;\n                z = be.b;\n            }\n        }\n\n        if (best_gain <= 0) {\n            if (!changed) break;\n            continue;\n        }\n\n        if (best_type == 1) {\n            apply_remove_aid(s, x);\n        } else if (best_type == 2) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n        } else if (best_type == 3) {\n            apply_add(s, x);\n            apply_add(s, y);\n        } else if (best_type == 4) {\n            apply_remove_aid(s, x);\n            apply_add(s, y);\n            apply_add(s, z);\n        }\n    }\n}\n\ntemplate <class RNG>\nSolution perturb_weak_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline, const ImproveParam& prm) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, prm);\n        return s;\n    }\n\n    int R = 2 + (int)(rng() % 4);\n    R = min(R, s.L);\n\n    vector<pair<long long, int>> rems;\n    rems.reserve(s.L);\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        int aid = s.ops[i];\n        long long gr = gain_remove(s, aid);\n        rems.push_back({gr, i});\n    }\n    sort(rems.begin(), rems.end(), [](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n\n    int pool = min<int>(12, rems.size());\n    vector<int> ids(pool);\n    iota(ids.begin(), ids.end(), 0);\n    vector<int> pick_idx;\n    pick_idx.reserve(R);\n\n    for (int t = 0; t < R && !ids.empty(); ++t) {\n        int lim = min<int>(6, ids.size());\n        int total_w = lim * (lim + 1) / 2;\n        int rr = (int)(rng() % total_w);\n        int acc = 0, choose_pos = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (lim - i);\n            if (rr < acc) {\n                choose_pos = i;\n                break;\n            }\n        }\n        int sel = ids[choose_pos];\n        pick_idx.push_back(rems[sel].second);\n        ids.erase(ids.begin() + choose_pos);\n    }\n\n    sort(pick_idx.begin(), pick_idx.end(), greater<int>());\n    for (int idx : pick_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, prm);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_random_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline, const ImproveParam& prm) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, prm);\n        return s;\n    }\n\n    int R = 2 + (int)(rng() % 6);\n    R = min(R, s.L);\n\n    vector<int> idxs(s.L);\n    iota(idxs.begin(), idxs.end(), 0);\n    shuffle(idxs.begin(), idxs.end(), rng);\n    idxs.resize(R);\n    sort(idxs.begin(), idxs.end(), greater<int>());\n\n    for (int idx : idxs) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, prm);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_cell_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline, const ImproveParam& prm) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, prm);\n        return s;\n    }\n\n    int c = (int)(rng() % CELL);\n    vector<int> rem_idx;\n    rem_idx.reserve(s.L);\n\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        int aid = s.ops[i];\n        if (action_touches_cell(aid, c)) rem_idx.push_back(i);\n    }\n\n    if (rem_idx.empty()) {\n        int R = min<int>(2 + (int)(rng() % 4), s.L);\n        vector<int> idxs(s.L);\n        iota(idxs.begin(), idxs.end(), 0);\n        shuffle(idxs.begin(), idxs.end(), rng);\n        rem_idx.assign(idxs.begin(), idxs.begin() + R);\n    } else {\n        shuffle(rem_idx.begin(), rem_idx.end(), rng);\n        int cap = 2 + (int)(rng() % 6);\n        if ((int)rem_idx.size() > cap) rem_idx.resize(cap);\n    }\n\n    sort(rem_idx.begin(), rem_idx.end(), greater<int>());\n    rem_idx.erase(unique(rem_idx.begin(), rem_idx.end()), rem_idx.end());\n    for (int idx : rem_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, prm);\n    return s;\n}\n\ntemplate <class RNG>\nSolution perturb_position_rebuild(const Solution& base, RNG& rng, const Timer& timer, double deadline, const ImproveParam& prm) {\n    Solution s = base;\n    if (s.L == 0) {\n        randomized_fill(s, rng, 18);\n        local_improve(s, timer, deadline, prm);\n        return s;\n    }\n\n    int p0 = (int)(rng() % POS);\n    int q0 = (int)(rng() % POS);\n    int dist = (rng() % 100 < 65 ? 0 : 1);\n\n    vector<int> rem_idx;\n    rem_idx.reserve(s.L);\n    for (int i = 0; i < (int)s.ops.size(); ++i) {\n        const auto& ac = actions[s.ops[i]];\n        int d = abs(ac.p - p0) + abs(ac.q - q0);\n        if (d <= dist) rem_idx.push_back(i);\n    }\n\n    if (rem_idx.empty()) {\n        int R = min<int>(2 + (int)(rng() % 4), s.L);\n        vector<int> idxs(s.L);\n        iota(idxs.begin(), idxs.end(), 0);\n        shuffle(idxs.begin(), idxs.end(), rng);\n        rem_idx.assign(idxs.begin(), idxs.begin() + R);\n    } else {\n        shuffle(rem_idx.begin(), rem_idx.end(), rng);\n        int cap = 2 + (int)(rng() % 7);\n        if ((int)rem_idx.size() > cap) rem_idx.resize(cap);\n    }\n\n    sort(rem_idx.begin(), rem_idx.end(), greater<int>());\n    rem_idx.erase(unique(rem_idx.begin(), rem_idx.end()), rem_idx.end());\n    for (int idx : rem_idx) apply_remove_index(s, idx);\n\n    randomized_fill(s, rng, 18);\n    local_improve(s, timer, deadline, prm);\n    return s;\n}\n\nvoid update_elites(vector<Solution>& elites, const Solution& cand) {\n    for (const auto& e : elites) {\n        if (e.score == cand.score && e.L == cand.L) return;\n    }\n    elites.push_back(cand);\n    sort(elites.begin(), elites.end(), [](const Solution& a, const Solution& b) {\n        return a.score > b.score;\n    });\n    if ((int)elites.size() > ELITE_CAP) elites.resize(ELITE_CAP);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N_in;\n    cin >> N_in >> M_in >> K_in;\n\n    for (int i = 0; i < N_in; ++i) {\n        for (int j = 0; j < N_in; ++j) {\n            cin >> init_r[i * N + j];\n        }\n    }\n\n    vector<array<array<int, 3>, 3>> stamps(M_in);\n    for (int m = 0; m < M_in; ++m) {\n        for (int i = 0; i < 3; ++i) {\n            for (int j = 0; j < 3; ++j) {\n                cin >> stamps[m][i][j];\n            }\n        }\n    }\n\n    actions.clear();\n    actions.reserve(M_in * POS * POS);\n    for (int m = 0; m < M_in; ++m) {\n        for (int p = 0; p <= N_in - 3; ++p) {\n            for (int q = 0; q <= N_in - 3; ++q) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                int t = 0;\n                for (int i = 0; i < 3; ++i) {\n                    for (int j = 0; j < 3; ++j) {\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.val[t] = stamps[m][i][j];\n                        ++t;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n    A = (int)actions.size();\n\n    for (int c = 0; c < CELL; ++c) cell_to_actions[c].clear();\n    for (int aid = 0; aid < A; ++aid) {\n        for (int k = 0; k < 9; ++k) {\n            cell_to_actions[actions[aid].cell[k]].push_back(aid);\n        }\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.84;\n    const double FINAL_RESERVE = 0.12;\n    const double MAIN_END = TIME_LIMIT - FINAL_RESERVE;\n\n    const ImproveParam normal_param{72, 160, 4, 32, 10};\n    const ImproveParam short_param{72, 160, 4, 32, 6};\n    const ImproveParam tiny_param{72, 160, 4, 32, 4};\n    const ImproveParam strong_param{96, 220, 5, 40, 8};\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count() ^\n        (uint64_t)(uintptr_t)new int\n    );\n\n    vector<Solution> elites;\n    elites.reserve(ELITE_CAP);\n\n    Solution best = build_greedy(false, rng);\n    local_improve(best, timer, MAIN_END, normal_param);\n    Solution current = best;\n    update_elites(elites, best);\n\n    while (timer.elapsed() < 0.24 && timer.elapsed() < MAIN_END) {\n        Solution s = build_greedy(true, rng);\n        local_improve(s, timer, MAIN_END, short_param);\n        if (s.score > best.score) {\n            best = s;\n            current = s;\n        }\n        update_elites(elites, s);\n    }\n\n    while (timer.elapsed() < MAIN_END) {\n        Solution base;\n        uint64_t rv = rng() % 100;\n        if (rv < 8) {\n            base = build_greedy(true, rng);\n            local_improve(base, timer, MAIN_END, tiny_param);\n        } else if (rv < 38) {\n            base = best;\n        } else if (rv < 68) {\n            base = current;\n        } else {\n            base = elites.empty() ? best : elites[(size_t)(rng() % elites.size())];\n        }\n\n        Solution cand;\n        uint64_t mode = rng() % 100;\n        if (mode < 35) {\n            cand = perturb_weak_rebuild(base, rng, timer, MAIN_END, short_param);\n        } else if (mode < 58) {\n            cand = perturb_random_rebuild(base, rng, timer, MAIN_END, short_param);\n        } else if (mode < 79) {\n            cand = perturb_cell_rebuild(base, rng, timer, MAIN_END, short_param);\n        } else {\n            cand = perturb_position_rebuild(base, rng, timer, MAIN_END, short_param);\n        }\n\n        if (cand.score > best.score) best = cand;\n        update_elites(elites, cand);\n\n        double progress = min(1.0, timer.elapsed() / MAIN_END);\n        long double T0 = 1.5e8L;\n        long double T1 = 4.0e5L;\n        long double temp = T0 * pow(T1 / T0, progress);\n\n        long long diff = cand.score - current.score;\n        bool accept = false;\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            long double prob = expl((long double)diff / temp);\n            long double u = (long double)(rng() >> 11) * (1.0L / (1ULL << 53));\n            if (u < prob) accept = true;\n        }\n\n        if (accept) current = cand;\n        if (current.score > best.score) best = current;\n        update_elites(elites, current);\n        update_elites(elites, best);\n    }\n\n    sort(elites.begin(), elites.end(), [](const Solution& a, const Solution& b) {\n        return a.score > b.score;\n    });\n\n    for (int i = 0; i < (int)elites.size() && i < 2 && timer.elapsed() < TIME_LIMIT; ++i) {\n        Solution s = elites[i];\n        local_improve(s, timer, TIME_LIMIT, strong_param);\n        final_exact_polish(s, timer, TIME_LIMIT);\n        if (s.score > best.score) best = s;\n        update_elites(elites, s);\n    }\n\n    while (timer.elapsed() < TIME_LIMIT) {\n        Solution base = elites.empty() ? best : elites[(size_t)(rng() % elites.size())];\n        Solution cand;\n        if (rng() % 100 < 55) {\n            cand = perturb_position_rebuild(base, rng, timer, TIME_LIMIT, tiny_param);\n        } else {\n            cand = perturb_cell_rebuild(base, rng, timer, TIME_LIMIT, tiny_param);\n        }\n\n        local_improve(cand, timer, TIME_LIMIT, strong_param);\n\n        double remain = TIME_LIMIT - timer.elapsed();\n        if (remain > 0.035 && (rng() % 100 < 35)) {\n            final_exact_polish(cand, timer, TIME_LIMIT);\n        }\n\n        if (cand.score > best.score) best = cand;\n        update_elites(elites, cand);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (int aid : best.ops) {\n        const auto& ac = actions[aid];\n        cout << ac.m << ' ' << ac.p << ' ' << ac.q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int TOTAL = 25;\nstatic constexpr int DYN_BUF = 5;\nstatic constexpr int CELL_CNT = 20;\nstatic constexpr int INF = 1e9;\nstatic constexpr int UNAVAIL = -2;\nstatic constexpr int EMPTY = -1;\n\nstruct Pos {\n    int r, c;\n};\n\nstatic int mdist(const Pos& a, const Pos& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\n\nstatic vector<char> make_route(Pos cur, Pos dst) {\n    vector<char> res;\n    while (cur.r < dst.r) res.push_back('D'), cur.r++;\n    while (cur.r > dst.r) res.push_back('U'), cur.r--;\n    while (cur.c < dst.c) res.push_back('R'), cur.c++;\n    while (cur.c > dst.c) res.push_back('L'), cur.c--;\n    return res;\n}\n\nstatic string macros_to_plan(const vector<pair<Pos, Pos>>& macros) {\n    string s;\n    Pos cur{0, 0};\n    for (auto [src, dst] : macros) {\n        auto p1 = make_route(cur, src);\n        for (char ch : p1) s.push_back(ch);\n        s.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) s.push_back(ch);\n        s.push_back('Q');\n        cur = dst;\n    }\n    if (s.empty()) s = \".\";\n    return s;\n}\n\nstruct TimeKeeper {\n    chrono::steady_clock::time_point st;\n    double limit_ms;\n    TimeKeeper(double limit_ms_) : st(chrono::steady_clock::now()), limit_ms(limit_ms_) {}\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    double remain_ms() const {\n        return limit_ms - elapsed_ms();\n    }\n    bool timeout() const {\n        return elapsed_ms() >= limit_ms;\n    }\n};\n\n// ============================================================\n// Simulator / evaluator\n// ============================================================\n\nstruct EvaluationResult {\n    bool legal = false;\n    long long score = (1LL << 60);\n    int turns = INF;\n};\n\nstruct Simulator {\n    int A[N][N];\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    };\n\n    Simulator(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n    }\n\n    EvaluationResult evaluate(const vector<string>& S) const {\n        int board[N][N];\n        int spawn_ptr[N];\n        bool dispatched[TOTAL];\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n\n        Crane cranes[N];\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n\n        int T = 0;\n        for (auto &s : S) T = max(T, (int)s.size());\n        if (T < 1 || T > 10000) return {};\n\n        vector<int> out_seq[N];\n\n        auto step_spawn = [&]() {\n            for (int r = 0; r < N; r++) {\n                if (spawn_ptr[r] >= N) continue;\n                if (board[r][0] != -1) continue;\n\n                bool blocked = false;\n                for (int i = 0; i < N; i++) {\n                    if (!cranes[i].alive) continue;\n                    if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                        blocked = true;\n                        break;\n                    }\n                }\n                if (blocked) continue;\n\n                board[r][0] = A[r][spawn_ptr[r]];\n                spawn_ptr[r]++;\n            }\n        };\n\n        for (int turn = 0; turn < T; turn++) {\n            step_spawn();\n\n            array<char, N> act;\n            array<int, N> nr, nc;\n            array<bool, N> final_alive, moving;\n\n            for (int i = 0; i < N; i++) {\n                act[i] = (turn < (int)S[i].size() ? S[i][turn] : '.');\n                nr[i] = cranes[i].r;\n                nc[i] = cranes[i].c;\n                final_alive[i] = cranes[i].alive;\n                moving[i] = false;\n            }\n\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) {\n                    if (act[i] != '.') return {};\n                    continue;\n                }\n                char a = act[i];\n                if (a == 'U') nr[i]--, moving[i] = true;\n                else if (a == 'D') nr[i]++, moving[i] = true;\n                else if (a == 'L') nc[i]--, moving[i] = true;\n                else if (a == 'R') nc[i]++, moving[i] = true;\n\n                if (a == 'U' || a == 'D' || a == 'L' || a == 'R') {\n                    if (nr[i] < 0 || nr[i] >= N || nc[i] < 0 || nc[i] >= N) return {};\n                    if (!cranes[i].large && cranes[i].hold != -1 && board[nr[i]][nc[i]] != -1) return {};\n                } else if (a == 'P') {\n                    if (cranes[i].hold != -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] == -1) return {};\n                } else if (a == 'Q') {\n                    if (cranes[i].hold == -1) return {};\n                    if (board[cranes[i].r][cranes[i].c] != -1) return {};\n                } else if (a == 'B') {\n                    if (cranes[i].hold != -1) return {};\n                    final_alive[i] = false;\n                } else if (a == '.') {\n                } else {\n                    return {};\n                }\n            }\n\n            for (int i = 0; i < N; i++) if (final_alive[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j]) {\n                    if (nr[i] == nr[j] && nc[i] == nc[j]) return {};\n                }\n            }\n\n            for (int i = 0; i < N; i++) if (final_alive[i] && moving[i]) {\n                for (int j = i + 1; j < N; j++) if (final_alive[j] && moving[j]) {\n                    if (nr[i] == cranes[j].r && nc[i] == cranes[j].c &&\n                        nr[j] == cranes[i].r && nc[j] == cranes[i].c) {\n                        return {};\n                    }\n                }\n            }\n\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                char a = act[i];\n                if (a == '.') {\n                } else if (a == 'B') {\n                    cranes[i].alive = false;\n                } else if (a == 'P') {\n                    cranes[i].hold = board[cranes[i].r][cranes[i].c];\n                    board[cranes[i].r][cranes[i].c] = -1;\n                } else if (a == 'Q') {\n                    board[cranes[i].r][cranes[i].c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                } else {\n                    cranes[i].r = nr[i];\n                    cranes[i].c = nc[i];\n                }\n            }\n\n            for (int r = 0; r < N; r++) {\n                if (board[r][4] != -1) {\n                    int b = board[r][4];\n                    board[r][4] = -1;\n                    if (b < 0 || b >= TOTAL) return {};\n                    if (dispatched[b]) return {};\n                    dispatched[b] = true;\n                    out_seq[r].push_back(b);\n                }\n            }\n        }\n\n        int M0 = T;\n        int M1 = 0, M2 = 0;\n        int dispatched_count = 0;\n\n        for (int r = 0; r < N; r++) {\n            vector<int> correct;\n            for (int b : out_seq[r]) {\n                dispatched_count++;\n                if (b / 5 != r) M2++;\n                else correct.push_back(b);\n            }\n            for (int i = 0; i < (int)correct.size(); i++) {\n                for (int j = i + 1; j < (int)correct.size(); j++) {\n                    if (correct[i] > correct[j]) M1++;\n                }\n            }\n        }\n\n        int M3 = TOTAL - dispatched_count;\n        long long score = 1LL * M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n        return {true, score, M0};\n    }\n};\n\n// ============================================================\n// One-crane macro search\n// ============================================================\n\nstruct MacroSearch {\n    int A[N][N];\n    array<Pos, CELL_CNT> cell_pos;\n\n    MacroSearch(int A_[N][N]) {\n        memcpy(A, A_, sizeof(A));\n        for (int r = 0; r < N; r++) cell_pos[r] = {r, 0};\n        int idx = DYN_BUF;\n        for (int r = 0; r < N; r++) for (int c = 1; c <= 3; c++) cell_pos[idx++] = {r, c};\n    }\n\n    struct Key {\n        uint64_t a, b, c;\n        bool operator==(const Key& o) const { return a == o.a && b == o.b && c == o.c; }\n    };\n    struct KeyHash {\n        size_t operator()(const Key& k) const {\n            uint64_t x = k.a;\n            x ^= k.b + 0x9e3779b97f4a7c15ULL + (x << 6) + (x >> 2);\n            x ^= k.c + 0x9e3779b97f4a7c15ULL + (x << 6) + (x >> 2);\n            return (size_t)x;\n        }\n    };\n\n    struct Action {\n        Pos src, dst;\n    };\n\n    struct State {\n        array<uint8_t, 5> ptr{};\n        array<uint8_t, 5> done{};\n        array<int8_t, CELL_CNT> cell{};\n        uint8_t pos = 0;\n        int g = INF;\n        int parent = -1;\n        Action act;\n    };\n\n    static int pos_to_idx(const Pos& p) { return p.r * 5 + p.c; }\n    static Pos idx_to_pos(int idx) { return Pos{idx / 5, idx % 5}; }\n\n    int current_need(const State& s, int tr) const {\n        return 5 * tr + s.done[tr];\n    }\n\n    static uint64_t enc_cell(int v) {\n        if (v == UNAVAIL) return 30;\n        if (v == EMPTY) return 31;\n        return (uint64_t)v;\n    }\n\n    Key pack(const State& s) const {\n        uint64_t out[3] = {0, 0, 0};\n        int sh = 0;\n        auto add = [&](uint64_t v, int bits) {\n            int idx = sh >> 6;\n            int off = sh & 63;\n            if (off + bits <= 64) out[idx] |= v << off;\n            else {\n                int low = 64 - off;\n                out[idx] |= v << off;\n                out[idx + 1] |= v >> low;\n            }\n            sh += bits;\n        };\n        for (int i = 0; i < 5; i++) add(s.ptr[i], 3);\n        for (int i = 0; i < 5; i++) add(s.done[i], 3);\n        add(s.pos, 5);\n        for (int i = 0; i < CELL_CNT; i++) add(enc_cell(s.cell[i]), 5);\n        return {out[0], out[1], out[2]};\n    }\n\n    int heuristic(const State& s) const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int k = s.ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            Pos p = cell_pos[i];\n            h += 2 + abs(p.r - tr) + (4 - p.c);\n        }\n        return h;\n    }\n\n    int visible_need_count(const State& s) const {\n        int cnt = 0;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) cnt++;\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b == current_need(s, tr)) cnt++;\n        }\n        return cnt;\n    }\n\n    int gate_need_count(const State& s) const {\n        int cnt = 0;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int dist_to_best_dispatchable(const State& s) const {\n        Pos cur = idx_to_pos(s.pos);\n        int best = 100;\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] < N) {\n                int b = A[r][s.ptr[r]];\n                int tr = b / 5;\n                if (b == current_need(s, tr)) best = min(best, mdist(cur, Pos{r, 0}));\n            }\n        }\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b == current_need(s, tr)) best = min(best, mdist(cur, cell_pos[i]));\n        }\n        return best == 100 ? 0 : best;\n    }\n\n    bool finished(const State& s) const {\n        for (int i = 0; i < 5; i++) if (s.done[i] != 5) return false;\n        return true;\n    }\n\n    vector<int> empty_cells(const State& s) const {\n        vector<int> v;\n        for (int i = 0; i < CELL_CNT; i++) if (s.cell[i] == EMPTY) v.push_back(i);\n        return v;\n    }\n\n    int next_need_gap_after_store(const State& s, int r) const {\n        for (int k = s.ptr[r] + 1; k < N; k++) {\n            int b = A[r][k];\n            int tr = b / 5;\n            if (b == current_need(s, tr)) return k - (s.ptr[r] + 1);\n        }\n        return INF;\n    }\n\n    void enumerate_dispatches(const State& s, vector<State>& nxt) const {\n        Pos cur = idx_to_pos(s.pos);\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= N) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.ptr[r]++;\n            if (t.ptr[r] == N) t.cell[r] = EMPTY;\n            Pos src{r, 0}, dst{tr, 4};\n            t.done[tr]++;\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n\n        for (int i = 0; i < CELL_CNT; i++) {\n            int b = s.cell[i];\n            if (b < 0) continue;\n            int tr = b / 5;\n            if (b != current_need(s, tr)) continue;\n\n            State t = s;\n            t.cell[i] = EMPTY;\n            Pos src = cell_pos[i], dst{tr, 4};\n            t.done[tr]++;\n            t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            t.pos = pos_to_idx(dst);\n            t.act = {src, dst};\n            nxt.push_back(t);\n        }\n    }\n\n    void enumerate_stores(const State& s, vector<State>& nxt, int topK) const {\n        Pos cur = idx_to_pos(s.pos);\n        auto empties = empty_cells(s);\n        if (empties.empty()) return;\n\n        for (int r = 0; r < N; r++) {\n            if (s.ptr[r] >= N) continue;\n            int b = A[r][s.ptr[r]];\n            int tr = b / 5;\n            if (b == current_need(s, tr)) continue;\n\n            int gap = next_need_gap_after_store(s, r);\n\n            vector<pair<tuple<int,int,int,int>, int>> cand;\n            cand.reserve(empties.size());\n            for (int idx : empties) {\n                Pos d = cell_pos[idx];\n                int local = mdist(Pos{r, 0}, d) + mdist(d, Pos{tr, 4});\n                int rowmis = abs(d.r - tr);\n                int colpref = -d.c;\n                int gapkey = (gap >= INF ? 100 : gap);\n                cand.push_back({{gapkey, local, rowmis, colpref}, idx});\n            }\n            sort(cand.begin(), cand.end());\n\n            int K = min<int>(topK, cand.size());\n            for (int z = 0; z < K; z++) {\n                int idx = cand[z].second;\n                State t = s;\n                t.ptr[r]++;\n                if (t.ptr[r] == N) t.cell[r] = EMPTY;\n                t.cell[idx] = b;\n                Pos src{r, 0}, dst = cell_pos[idx];\n                t.g = s.g + mdist(cur, src) + 1 + mdist(src, dst) + 1;\n                t.pos = pos_to_idx(dst);\n                t.act = {src, dst};\n                nxt.push_back(t);\n            }\n        }\n    }\n\n    string reconstruct(const vector<State>& states, int id) const {\n        vector<pair<Pos, Pos>> macros;\n        int cur = id;\n        while (states[cur].parent != -1) {\n            macros.push_back({states[cur].act.src, states[cur].act.dst});\n            cur = states[cur].parent;\n        }\n        reverse(macros.begin(), macros.end());\n        return macros_to_plan(macros);\n    }\n\n    optional<string> solve_astar(TimeKeeper& tk, double local_ms, int state_limit, int topK, int upper_bound = INF) const {\n        if (tk.remain_ms() < 80) return nullopt;\n        auto local_start = chrono::steady_clock::now();\n        auto local_elapsed = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - local_start).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 5; i++) init.cell[i] = UNAVAIL;\n        for (int i = 5; i < CELL_CNT; i++) init.cell[i] = EMPTY;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        int h0 = heuristic(init);\n        if (h0 >= upper_bound) return nullopt;\n\n        struct PQNode {\n            int f, g, id;\n            bool operator<(const PQNode& o) const {\n                if (f != o.f) return f > o.f;\n                return g > o.g;\n            }\n        };\n\n        vector<State> states;\n        states.reserve(state_limit + 1000);\n        states.push_back(init);\n\n        unordered_map<Key, int, KeyHash> best;\n        best.reserve(state_limit * 2);\n        best[pack(init)] = 0;\n\n        priority_queue<PQNode> pq;\n        pq.push({h0, 0, 0});\n\n        while (!pq.empty() &&\n               (int)states.size() < state_limit &&\n               local_elapsed() < local_ms &&\n               !tk.timeout()) {\n            auto [f, g, id] = pq.top();\n            pq.pop();\n            if (f >= upper_bound) continue;\n            if (states[id].g != g) continue;\n            const State& s = states[id];\n\n            if (finished(s)) {\n                if (s.g < upper_bound) return reconstruct(states, id);\n                continue;\n            }\n\n            vector<State> nxt;\n            nxt.reserve(96);\n            enumerate_dispatches(s, nxt);\n            enumerate_stores(s, nxt, topK);\n\n            for (State &t : nxt) {\n                if (t.g >= upper_bound) continue;\n                int h = heuristic(t);\n                if (t.g + h >= upper_bound) continue;\n\n                t.parent = id;\n                Key k = pack(t);\n                auto it = best.find(k);\n                if (it != best.end()) {\n                    int oid = it->second;\n                    if (states[oid].g <= t.g) continue;\n                    it->second = (int)states.size();\n                } else {\n                    best.emplace(k, (int)states.size());\n                }\n\n                states.push_back(t);\n                pq.push({t.g + h, t.g, (int)states.size() - 1});\n            }\n        }\n\n        return nullopt;\n    }\n\n    optional<string> solve_beam(TimeKeeper& tk, double local_ms, int width, int mode, int topK, int upper_bound = INF) const {\n        if (tk.remain_ms() < 60) return nullopt;\n        auto local_start = chrono::steady_clock::now();\n        auto local_elapsed = [&]() -> double {\n            return chrono::duration<double, milli>(chrono::steady_clock::now() - local_start).count();\n        };\n\n        State init;\n        for (int i = 0; i < 5; i++) init.ptr[i] = 0, init.done[i] = 0;\n        for (int i = 0; i < 5; i++) init.cell[i] = UNAVAIL;\n        for (int i = 5; i < CELL_CNT; i++) init.cell[i] = EMPTY;\n        init.pos = 0;\n        init.g = 0;\n        init.parent = -1;\n\n        int h0 = heuristic(init);\n        if (h0 >= upper_bound) return nullopt;\n\n        vector<State> states;\n        states.reserve(350000);\n        states.push_back(init);\n\n        auto eval_value = [&](const State& s, int h) -> long long {\n            int vneed = visible_need_count(s);\n            int gneed = gate_need_count(s);\n            int dnear = dist_to_best_dispatchable(s);\n            long long val = 1LL * s.g + h;\n            if (mode == 0) {\n            } else if (mode == 1) {\n                val -= 3LL * vneed;\n                val -= 2LL * gneed;\n            } else if (mode == 2) {\n                val -= 2LL * vneed;\n                val += dnear;\n            } else if (mode == 3) {\n                val -= 4LL * gneed;\n                val += dnear;\n            } else {\n                val -= 2LL * vneed;\n                val -= 1LL * gneed;\n                val += 2LL * dnear;\n            }\n            return val;\n        };\n\n        vector<int> cur{0};\n        int best_finished = -1;\n        int max_depth = 70;\n\n        for (int depth = 0;\n             depth < max_depth && !cur.empty() && local_elapsed() < local_ms && !tk.timeout();\n             depth++) {\n            unordered_map<Key, pair<long long, int>, KeyHash> mp;\n            mp.reserve(width * 30);\n\n            for (int id : cur) {\n                const State& s = states[id];\n                int hs = heuristic(s);\n                if (s.g + hs >= upper_bound) continue;\n\n                if (finished(s)) {\n                    if (s.g < upper_bound) {\n                        if (best_finished == -1 || states[id].g < states[best_finished].g) best_finished = id;\n                    }\n                    continue;\n                }\n\n                vector<State> nxt;\n                nxt.reserve(96);\n                enumerate_dispatches(s, nxt);\n                enumerate_stores(s, nxt, topK);\n\n                for (State &t : nxt) {\n                    if (t.g >= upper_bound) continue;\n                    int h = heuristic(t);\n                    if (t.g + h >= upper_bound) continue;\n\n                    t.parent = id;\n                    int nid = (int)states.size();\n                    states.push_back(t);\n\n                    if (finished(t)) {\n                        if (t.g < upper_bound) {\n                            if (best_finished == -1 || t.g < states[best_finished].g) best_finished = nid;\n                        }\n                        continue;\n                    }\n\n                    Key k = pack(t);\n                    long long ev = eval_value(t, h);\n                    auto it = mp.find(k);\n                    if (it == mp.end() || ev < it->second.first ||\n                        (ev == it->second.first && t.g < states[it->second.second].g)) {\n                        mp[k] = {ev, nid};\n                    }\n                }\n            }\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(mp.size());\n            for (auto &kv : mp) cand.push_back({kv.second.first, kv.second.second});\n            sort(cand.begin(), cand.end(), [&](auto &x, auto &y) {\n                if (x.first != y.first) return x.first < y.first;\n                return states[x.second].g < states[y.second].g;\n            });\n\n            cur.clear();\n            for (int i = 0; i < (int)cand.size() && i < width; i++) cur.push_back(cand[i].second);\n\n            if (best_finished != -1 && depth >= 20) break;\n        }\n\n        if (best_finished != -1) return reconstruct(states, best_finished);\n        return nullopt;\n    }\n};\n\n// ============================================================\n// Greedy solver\n// ============================================================\n\nstruct GreedyParam {\n    int dispatch_mode = 0;\n    int store_mode = 0;\n    int unlock_bonus = 0;\n};\n\nstruct GreedySolver {\n    int A[N][N];\n    GreedyParam param;\n\n    int board[N][N];\n    int spawn_ptr[N];\n    bool dispatched[TOTAL];\n    int total_dispatched = 0;\n\n    struct Crane {\n        int r, c;\n        int hold;\n        bool alive;\n        bool large;\n    } cranes[N];\n\n    string out[N];\n    deque<char> plan;\n\n    GreedySolver(int A_[N][N], GreedyParam p) : param(p) {\n        memcpy(A, A_, sizeof(A));\n        memset(board, -1, sizeof(board));\n        memset(spawn_ptr, 0, sizeof(spawn_ptr));\n        memset(dispatched, 0, sizeof(dispatched));\n        cranes[0] = {0, 0, -1, true, true};\n        for (int i = 1; i < N; i++) cranes[i] = {i, 0, -1, true, false};\n    }\n\n    int current_need(int tr) const {\n        for (int x = 5 * tr; x < 5 * tr + 5; x++) if (!dispatched[x]) return x;\n        return 5 * tr + 5;\n    }\n\n    int inversion_increase_if_dispatch_now(int b) const {\n        int tr = b / 5;\n        int cnt = 0;\n        for (int x = 5 * tr; x < b; x++) if (!dispatched[x]) cnt++;\n        return cnt;\n    }\n\n    int remaining_lb() const {\n        int h = 0;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= 3; c++) {\n                int b = board[r][c];\n                if (b == -1) continue;\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + (4 - c);\n            }\n        }\n        for (int r = 0; r < N; r++) {\n            for (int k = spawn_ptr[r]; k < N; k++) {\n                int b = A[r][k];\n                int tr = b / 5;\n                h += 2 + abs(r - tr) + 4;\n            }\n        }\n        return h;\n    }\n\n    deque<char> make_transport_plan(Pos src, Pos dst) const {\n        deque<char> q;\n        auto p1 = make_route(Pos{cranes[0].r, cranes[0].c}, src);\n        for (char ch : p1) q.push_back(ch);\n        q.push_back('P');\n        auto p2 = make_route(src, dst);\n        for (char ch : p2) q.push_back(ch);\n        q.push_back('Q');\n        return q;\n    }\n\n    bool is_buffer_cell_empty(int r, int c) const {\n        if (c == 4) return false;\n        if (board[r][c] != -1) return false;\n        if (1 <= c && c <= 3) return true;\n        if (c == 0 && spawn_ptr[r] == N) return true;\n        return false;\n    }\n\n    vector<Pos> available_buffer_cells() const {\n        vector<Pos> v;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) if (is_buffer_cell_empty(r, c)) v.push_back({r, c});\n            if (is_buffer_cell_empty(r, 0)) v.push_back({r, 0});\n        }\n        return v;\n    }\n\n    int next_need_gap_after_storing_row(int r) const {\n        for (int k = spawn_ptr[r]; k < N; k++) {\n            int b = A[r][k];\n            int tr = b / 5;\n            if (!dispatched[b] && b == current_need(tr)) return k - spawn_ptr[r];\n        }\n        return INF;\n    }\n\n    struct Cand {\n        long long k1 = (1LL << 60), k2 = (1LL << 60), k3 = (1LL << 60);\n        Pos src{-1, -1}, dst{-1, -1};\n        bool ok = false;\n    };\n\n    optional<deque<char>> choose_dispatch_plan() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b != current_need(tr)) continue;\n\n            Pos src{r, c}, dst{tr, 4};\n            int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            int after_h = base_h - (2 + abs(r - tr) + (4 - c));\n\n            long long k1, k2, k3;\n            if (param.dispatch_mode == 0) {\n                k1 = immediate;\n                k2 = (c == 0 ? 0 : 1);\n                k3 = after_h;\n            } else if (param.dispatch_mode == 1) {\n                k1 = immediate + after_h;\n                k2 = immediate;\n                k3 = (c == 0 ? 0 : 1);\n            } else if (param.dispatch_mode == 2) {\n                k1 = immediate + after_h - (c == 0 ? 3 : 0);\n                k2 = immediate;\n                k3 = after_h;\n            } else {\n                k1 = abs(cur.r - r);\n                k2 = immediate;\n                k3 = after_h;\n            }\n\n            if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                best = {k1, k2, k3, src, dst, true};\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_store_plan() const {\n        auto buf = available_buffer_cells();\n        if (buf.empty()) return nullopt;\n\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n        int base_h = remaining_lb();\n\n        for (int r = 0; r < N; r++) {\n            if (board[r][0] == -1) continue;\n            if (spawn_ptr[r] == N) continue;\n\n            int b = board[r][0];\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n\n            int gap = next_need_gap_after_storing_row(r);\n            int unlock = (gap >= INF ? 0 : max(0, 5 - gap));\n            int old_cost = 2 + abs(r - tr) + 4;\n\n            for (auto d : buf) {\n                int new_cost = 2 + abs(d.r - tr) + (4 - d.c);\n                int immediate = mdist(cur, Pos{r, 0}) + 1 + mdist(Pos{r, 0}, d) + 1;\n                int after_h = base_h - old_cost + new_cost;\n\n                long long k1, k2, k3;\n                if (param.store_mode == 0) {\n                    k1 = gap;\n                    k2 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k3 = new_cost;\n                } else if (param.store_mode == 1) {\n                    k1 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                    k2 = gap;\n                    k3 = new_cost;\n                } else if (param.store_mode == 2) {\n                    k1 = immediate;\n                    k2 = gap;\n                    k3 = after_h;\n                } else {\n                    k1 = new_cost;\n                    k2 = gap;\n                    k3 = immediate + after_h - 1LL * param.unlock_bonus * unlock;\n                }\n\n                if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                    best = {k1, k2, k3, Pos{r, 0}, d, true};\n                }\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    optional<deque<char>> choose_forced_early_dispatch() const {\n        Cand best;\n        Pos cur{cranes[0].r, cranes[0].c};\n\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            int b = board[r][c];\n            if (b == -1) continue;\n            int tr = b / 5;\n            if (b == current_need(tr)) continue;\n\n            int inv = inversion_increase_if_dispatch_now(b);\n            Pos src{r, c}, dst{tr, 4};\n            int immediate = mdist(cur, src) + 1 + mdist(src, dst) + 1;\n            long long k1 = inv;\n            long long k2 = immediate;\n            long long k3 = (c == 0 ? 0 : 1);\n\n            if (!best.ok || tie(k1, k2, k3) < tie(best.k1, best.k2, best.k3)) {\n                best = {k1, k2, k3, src, dst, true};\n            }\n        }\n\n        if (!best.ok) return nullopt;\n        return make_transport_plan(best.src, best.dst);\n    }\n\n    deque<char> choose_next_plan() const {\n        if (auto p = choose_dispatch_plan()) return *p;\n        if (auto p = choose_store_plan()) return *p;\n        if (auto p = choose_forced_early_dispatch()) return *p;\n        return {};\n    }\n\n    void step_spawn() {\n        for (int r = 0; r < N; r++) {\n            if (spawn_ptr[r] >= N) continue;\n            if (board[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (blocked) continue;\n\n            board[r][0] = A[r][spawn_ptr[r]];\n            spawn_ptr[r]++;\n        }\n    }\n\n    void apply_action(int idx, char act) {\n        auto &cr = cranes[idx];\n        if (!cr.alive) return;\n        if (act == '.') return;\n        if (act == 'B') {\n            cr.alive = false;\n            return;\n        }\n        if (act == 'P') {\n            cr.hold = board[cr.r][cr.c];\n            board[cr.r][cr.c] = -1;\n            return;\n        }\n        if (act == 'Q') {\n            board[cr.r][cr.c] = cr.hold;\n            cr.hold = -1;\n            return;\n        }\n        if (act == 'U') cr.r--;\n        if (act == 'D') cr.r++;\n        if (act == 'L') cr.c--;\n        if (act == 'R') cr.c++;\n    }\n\n    void step_dispatch() {\n        for (int r = 0; r < N; r++) {\n            if (board[r][4] != -1) {\n                int b = board[r][4];\n                board[r][4] = -1;\n                if (!dispatched[b]) {\n                    dispatched[b] = true;\n                    total_dispatched++;\n                }\n            }\n        }\n    }\n\n    vector<string> solve() {\n        int turn = 0;\n        while (total_dispatched < TOTAL && turn < 10000) {\n            step_spawn();\n\n            array<char, N> act;\n            act.fill('.');\n            if (turn == 0) {\n                for (int i = 1; i < N; i++) act[i] = 'B';\n            }\n\n            if (plan.empty()) plan = choose_next_plan();\n            if (!plan.empty()) {\n                act[0] = plan.front();\n                plan.pop_front();\n            }\n\n            for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n            for (int i = 0; i < N; i++) apply_action(i, act[i]);\n            step_dispatch();\n            turn++;\n        }\n\n        vector<string> res(N);\n        for (int i = 0; i < N; i++) res[i] = out[i];\n        if (res[0].empty()) res[0] = \".\";\n        for (int i = 1; i < N; i++) if (res[i].empty()) res[i] = \"B\";\n        return res;\n    }\n};\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A[i][j];\n\n    TimeKeeper tk(2800.0);\n    Simulator sim(A);\n    MacroSearch ms(A);\n\n    vector<string> baseline_candidate;\n    long long best_score = (1LL << 60);\n    vector<string> best_ans;\n    int best_exact_turns = INF;\n\n    unordered_set<string> seen;\n    seen.reserve(512);\n\n    auto norm = [&](const vector<string>& S) -> string {\n        string t;\n        for (int i = 0; i < N; i++) {\n            t += S[i];\n            t.push_back('#');\n        }\n        return t;\n    };\n\n    auto consider_candidate = [&](const vector<string>& cand) {\n        string key = norm(cand);\n        if (!seen.insert(key).second) return;\n\n        auto ev = sim.evaluate(cand);\n        if (!ev.legal) return;\n\n        if (ev.score < best_score) {\n            best_score = ev.score;\n            best_ans = cand;\n        }\n        if (ev.score == ev.turns) {\n            best_exact_turns = min(best_exact_turns, ev.turns);\n        }\n    };\n\n    auto consider_onecrane_plan = [&](const optional<string>& plan) {\n        if (!plan.has_value()) return;\n        vector<string> S(N);\n        S[0] = *plan;\n        for (int i = 1; i < N; i++) S[i] = \"B\";\n        consider_candidate(S);\n    };\n\n    vector<GreedyParam> params = {\n        {0, 0, 4},\n        {1, 0, 5},\n        {1, 1, 6},\n        {2, 1, 4},\n        {0, 2, 3},\n        {3, 3, 5},\n        {2, 0, 5},\n        {1, 3, 4},\n        {0, 1, 2},\n        {2, 2, 6},\n        {3, 0, 4},\n        {3, 1, 6},\n        {1, 2, 4},\n        {2, 3, 2},\n\n        // extra cheap variants\n        {0, 0, 6},\n        {1, 1, 4},\n        {2, 1, 6},\n        {2, 2, 4},\n        {0, 3, 4},\n        {3, 2, 4},\n        {1, 0, 3},\n        {0, 2, 5},\n        {2, 0, 3},\n        {1, 3, 6},\n    };\n\n    bool first = true;\n    for (auto p : params) {\n        if (tk.timeout()) break;\n        GreedySolver gs(A, p);\n        auto cand = gs.solve();\n        if (first) {\n            baseline_candidate = cand;\n            first = false;\n        }\n        consider_candidate(cand);\n    }\n\n    int ub = best_exact_turns;\n\n    // strong main portfolio\n    consider_onecrane_plan(ms.solve_astar(tk, 650.0, 320000, 6, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_astar(tk, 450.0, 220000, 8, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_beam(tk, 280.0, 1400, 0, 6, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_beam(tk, 280.0, 1600, 1, 6, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_beam(tk, 280.0, 1600, 2, 7, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_beam(tk, 250.0, 1600, 3, 7, ub));\n    ub = best_exact_turns;\n    consider_onecrane_plan(ms.solve_beam(tk, 280.0, 1800, 4, 7, ub));\n\n    // low-risk extras\n    if (best_exact_turns < INF && tk.remain_ms() > 170.0) {\n        consider_onecrane_plan(ms.solve_beam(\n            tk,\n            min(140.0, tk.remain_ms() - 20.0),\n            1000,\n            2,\n            5,\n            best_exact_turns\n        ));\n    }\n\n    if (best_exact_turns < INF && tk.remain_ms() > 190.0) {\n        consider_onecrane_plan(ms.solve_beam(\n            tk,\n            min(160.0, tk.remain_ms() - 20.0),\n            1200,\n            1,\n            9,\n            best_exact_turns\n        ));\n    }\n\n    if (best_exact_turns < INF && tk.remain_ms() > 230.0) {\n        consider_onecrane_plan(ms.solve_astar(\n            tk,\n            min(220.0, tk.remain_ms() - 20.0),\n            180000,\n            5,\n            best_exact_turns\n        ));\n    }\n\n    if (best_ans.empty()) best_ans = baseline_candidate;\n\n    for (int i = 0; i < N; i++) {\n        cout << best_ans[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Solver {\n    int N, M;\n    vector<int> val;\n    vector<int> nz_ids;\n    vector<int> pos_ids;\n    int dmat[400][400];\n\n    ll best_var = INF64;\n    int best_kind = -1; // 0 = circular order, 1 = tree\n    vector<int> best_circle;\n    int best_start = 0;\n\n    struct TreePlan {\n        int root = -1;\n        int orient = 0;\n        vector<vector<int>> children;\n        vector<int> parent, sum, sz;\n        ll var_cost = INF64;\n    } best_tree;\n\n    vector<pair<ll, vector<int>>> seed_pool;\n    unordered_set<uint64_t> seed_hashes;\n\n    vector<string> ans;\n    int cur_r = 0, cur_c = 0;\n    ll truck = 0;\n\n    chrono::steady_clock::time_point global_deadline;\n\n    Solver(int N_, const vector<vector<int>>& h) : N(N_) {\n        M = N * N;\n        val.assign(M, 0);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                val[v] = h[r][c];\n                if (val[v] != 0) nz_ids.push_back(v);\n                if (val[v] > 0) pos_ids.push_back(v);\n            }\n        }\n        for (int a = 0; a < M; ++a) {\n            auto [ra, ca] = rc(a);\n            for (int b = 0; b < M; ++b) {\n                auto [rb, cb] = rc(b);\n                dmat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    int id(int r, int c) const { return r * N + c; }\n    pair<int,int> rc(int v) const { return {v / N, v % N}; }\n    int dist0(int v) const { return dmat[0][v]; }\n    int dist(int a, int b) const { return dmat[a][b]; }\n\n    static bool time_over(const chrono::steady_clock::time_point& end_time) {\n        return chrono::steady_clock::now() >= end_time;\n    }\n\n    // ============================================================\n    // Circular-order evaluation\n    // ============================================================\n    struct EvalRes {\n        ll cost;\n        int start;\n    };\n\n    EvalRes eval_circle(const vector<int>& seq) const {\n        int K = (int)seq.size();\n        if (K == 0) return {0, 0};\n\n        static ll pref[405];\n        static int ed[405];\n\n        pref[0] = 0;\n        for (int i = 0; i < K; ++i) pref[i + 1] = pref[i] + val[seq[i]];\n\n        ll mn = pref[0];\n        for (int s = 1; s < K; ++s) mn = min(mn, pref[s]);\n\n        ll total_edge = 0;\n        ll loaded_const = 0;\n        for (int i = 0; i < K; ++i) {\n            int j = (i + 1 == K ? 0 : i + 1);\n            ed[i] = dist(seq[i], seq[j]);\n            total_edge += ed[i];\n            loaded_const += (pref[i + 1] - mn) * 1LL * ed[i];\n        }\n\n        ll best = INF64;\n        int bestS = 0;\n        for (int s = 0; s < K; ++s) {\n            if (pref[s] != mn) continue;\n            int omitted = ed[(s - 1 + K) % K];\n            ll var = 100LL * (total_edge - omitted + dist0(seq[s])) + loaded_const;\n            if (var < best) {\n                best = var;\n                bestS = s;\n            }\n        }\n        return {best, bestS};\n    }\n\n    void update_best_circle(const vector<int>& seq, const EvalRes& ev) {\n        if (ev.cost < best_var) {\n            best_var = ev.cost;\n            best_kind = 0;\n            best_circle = seq;\n            best_start = ev.start;\n        }\n    }\n\n    uint64_t hash_seq(const vector<int>& seq) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : seq) {\n            uint64_t z = (uint64_t)(x + 1) * 0x9e3779b97f4a7c15ULL;\n            h ^= z;\n            h *= 1099511628211ULL;\n        }\n        h ^= (uint64_t)seq.size() + 0x517cc1b727220a95ULL;\n        return h;\n    }\n\n    void add_seed_if_new(const vector<int>& seq, ll cost) {\n        uint64_t h = hash_seq(seq);\n        if (seed_hashes.insert(h).second) {\n            seed_pool.push_back({cost, seq});\n        }\n    }\n\n    void consider_circle(const vector<int>& seq) {\n        EvalRes ev = eval_circle(seq);\n        update_best_circle(seq, ev);\n        add_seed_if_new(seq, ev.cost);\n    }\n\n    // ============================================================\n    // Base order generators\n    // ============================================================\n    pair<int,int> transform_point(pair<int,int> p, int flip, int rot) const {\n        int r = p.first, c = p.second;\n        if (flip) c = N - 1 - c;\n        for (int k = 0; k < rot; ++k) {\n            int nr = c;\n            int nc = N - 1 - r;\n            r = nr;\n            c = nc;\n        }\n        return {r, c};\n    }\n\n    vector<int> transform_and_compress(const vector<pair<int,int>>& base, int flip, int rot, bool rev) const {\n        vector<int> seq;\n        seq.reserve(nz_ids.size());\n        if (!rev) {\n            for (auto p : base) {\n                auto q = transform_point(p, flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        } else {\n            for (int i = (int)base.size() - 1; i >= 0; --i) {\n                auto q = transform_point(base[i], flip, rot);\n                int v = id(q.first, q.second);\n                if (val[v] != 0) seq.push_back(v);\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_row_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            if ((r & 1) == 0) {\n                for (int c = 0; c < N; ++c) seq.push_back({r, c});\n            } else {\n                for (int c = N - 1; c >= 0; --c) seq.push_back({r, c});\n            }\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_canonical_cycle_like() const {\n        vector<pair<int,int>> cyc;\n        cyc.reserve(M);\n        for (int c = 0; c < N; ++c) cyc.push_back({0, c});\n        for (int r = 1; r < N; ++r) {\n            if (r & 1) {\n                for (int c = N - 1; c >= 1; --c) cyc.push_back({r, c});\n            } else {\n                for (int c = 1; c < N; ++c) cyc.push_back({r, c});\n            }\n        }\n        for (int r = N - 1; r >= 1; --r) cyc.push_back({r, 0});\n        return cyc;\n    }\n\n    vector<pair<int,int>> make_diag_snake() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            vector<pair<int,int>> tmp;\n            int r0 = max(0, s - (N - 1));\n            int r1 = min(N - 1, s);\n            for (int r = r0; r <= r1; ++r) tmp.push_back({r, s - r});\n            if (s & 1) reverse(tmp.begin(), tmp.end());\n            for (auto p : tmp) seq.push_back(p);\n        }\n        return seq;\n    }\n\n    vector<pair<int,int>> make_block_snake(int B) const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        vector<int> block_cols;\n        for (int bc = 0; bc < N; bc += B) block_cols.push_back(bc);\n\n        for (int br = 0; br < N; br += B) {\n            auto bcs = block_cols;\n            if (((br / B) & 1) == 1) reverse(bcs.begin(), bcs.end());\n            for (int bc : bcs) {\n                int rlim = min(N, br + B);\n                int clim = min(N, bc + B);\n                for (int r = br; r < rlim; ++r) {\n                    if (((r - br) & 1) == 0) {\n                        for (int c = bc; c < clim; ++c) seq.push_back({r, c});\n                    } else {\n                        for (int c = clim - 1; c >= bc; --c) seq.push_back({r, c});\n                    }\n                }\n            }\n        }\n        return seq;\n    }\n\n    static void hilbert_rot(int n, int &x, int &y, int rx, int ry) {\n        if (ry == 0) {\n            if (rx == 1) {\n                x = n - 1 - x;\n                y = n - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    static int hilbert_xy2d(int n, int x, int y) {\n        int rx, ry, s, d = 0;\n        for (s = n / 2; s > 0; s /= 2) {\n            rx = (x & s) ? 1 : 0;\n            ry = (y & s) ? 1 : 0;\n            d += s * s * ((3 * rx) ^ ry);\n            hilbert_rot(n, x, y, rx, ry);\n        }\n        return d;\n    }\n\n    static unsigned morton_xy2d(unsigned x, unsigned y) {\n        auto part1by1 = [](unsigned x) -> unsigned {\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        };\n        return (part1by1(y) << 1) | part1by1(x);\n    }\n\n    vector<pair<int,int>> make_hilbert_order() const {\n        vector<pair<int, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        int S = 32;\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int d = hilbert_xy2d(S, c, r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) { return a.first < b.first; });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_morton_order() const {\n        vector<pair<unsigned, pair<int,int>>> tmp;\n        tmp.reserve(M);\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                unsigned d = morton_xy2d((unsigned)c, (unsigned)r);\n                tmp.push_back({d, {r, c}});\n            }\n        }\n        sort(tmp.begin(), tmp.end(), [](auto& a, auto& b) { return a.first < b.first; });\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        for (auto& e : tmp) seq.push_back(e.second);\n        return seq;\n    }\n\n    vector<pair<int,int>> make_spiral() const {\n        vector<pair<int,int>> seq;\n        seq.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; ++c) seq.push_back({top, c});\n            ++top;\n            for (int r = top; r <= bottom; ++r) seq.push_back({r, right});\n            --right;\n            if (top <= bottom) {\n                for (int c = right; c >= left; --c) seq.push_back({bottom, c});\n                --bottom;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; --r) seq.push_back({r, left});\n                ++left;\n            }\n        }\n        return seq;\n    }\n\n    void try_geometric_orders() {\n        vector<vector<pair<int,int>>> bases;\n        bases.push_back(make_row_snake());\n        bases.push_back(make_canonical_cycle_like());\n        bases.push_back(make_diag_snake());\n        bases.push_back(make_block_snake(2));\n        bases.push_back(make_block_snake(4));\n        bases.push_back(make_block_snake(5));\n        bases.push_back(make_hilbert_order());\n        bases.push_back(make_morton_order());\n        bases.push_back(make_spiral());\n\n        for (const auto& base : bases) {\n            for (int flip = 0; flip < 2; ++flip) {\n                for (int rot = 0; rot < 4; ++rot) {\n                    for (int rev = 0; rev < 2; ++rev) {\n                        auto seq = transform_and_compress(base, flip, rot, rev);\n                        consider_circle(seq);\n                    }\n                }\n            }\n        }\n    }\n\n    void try_projection_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        vector<pair<int,int>> coeffs = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {2,-1}, {1,-2}\n        };\n\n        for (auto [a, b] : coeffs) {\n            for (int sr : {-1, 1}) {\n                for (int sc : {-1, 1}) {\n                    vector<int> seq = nz_ids;\n                    sort(seq.begin(), seq.end(), [&](int x, int y) {\n                        auto [rx, cx] = rc(x);\n                        auto [ry, cy] = rc(y);\n                        int p1 = a * sr * rx + b * sc * cx;\n                        int p2 = a * sr * ry + b * sc * cy;\n                        if (p1 != p2) return p1 < p2;\n                        int q1 = b * sr * rx - a * sc * cx;\n                        int q2 = b * sr * ry - a * sc * cy;\n                        if (q1 != q2) return q1 < q2;\n                        return x < y;\n                    });\n                    consider_circle(seq);\n                    reverse(seq.begin(), seq.end());\n                    consider_circle(seq);\n                }\n            }\n        }\n    }\n\n    vector<int> select_greedy_starts() const {\n        vector<int> starts;\n        vector<char> seen(M, 0);\n\n        auto add = [&](int v) {\n            if (v == -1) {\n                starts.push_back(v);\n                return;\n            }\n            if (!seen[v]) {\n                seen[v] = 1;\n                starts.push_back(v);\n            }\n        };\n\n        add(-1);\n\n        if ((int)pos_ids.size() <= 40) {\n            for (int v : pos_ids) add(v);\n            return starts;\n        }\n\n        vector<int> tmp = pos_ids;\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (val[a] != val[b]) return val[a] > val[b];\n            return dist0(a) < dist0(b);\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            if (dist0(a) != dist0(b)) return dist0(a) < dist0(b);\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n            int sa = 5 * val[a] - 3 * dist0(a);\n            int sb = 5 * val[b] - 3 * dist0(b);\n            if (sa != sb) return sa > sb;\n            return val[a] > val[b];\n        });\n        for (int i = 0; i < min(20, (int)tmp.size()); ++i) add(tmp[i]);\n\n        return starts;\n    }\n\n    vector<int> build_greedy_linear(int lambda, int start_id) const {\n        int K = (int)nz_ids.size();\n        vector<char> used(M, 0);\n        vector<int> seq;\n        seq.reserve(K);\n\n        ll load = 0;\n        int cur = -1;\n\n        if (start_id != -1) {\n            used[start_id] = 1;\n            seq.push_back(start_id);\n            load += val[start_id];\n            cur = start_id;\n        }\n\n        while ((int)seq.size() < K) {\n            bool has_feasible_neg = false;\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                if (val[v] < 0 && load >= -1LL * val[v]) {\n                    has_feasible_neg = true;\n                    break;\n                }\n            }\n\n            int best = -1;\n            ll best_score = INF64;\n            int best_d = 0;\n            int best_gain = 0;\n\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                int hv = val[v];\n\n                if (has_feasible_neg) {\n                    if (hv >= 0) continue;\n                    if (load < -1LL * hv) continue;\n                } else {\n                    if (hv <= 0) continue;\n                }\n\n                int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                int gain = abs(hv);\n                ll score = (hv < 0 ? 1LL * lambda * d - 2LL * gain\n                                   : 1LL * lambda * d - 1LL * gain);\n\n                if (best == -1 ||\n                    score < best_score ||\n                    (score == best_score && (d < best_d ||\n                    (d == best_d && gain > best_gain)))) {\n                    best = v;\n                    best_score = score;\n                    best_d = d;\n                    best_gain = gain;\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) {\n                    if (used[v]) continue;\n                    if (val[v] <= 0) continue;\n                    int d = (cur == -1 ? dist0(v) : dist(cur, v));\n                    int gain = abs(val[v]);\n                    ll score = 1LL * lambda * d - gain;\n                    if (best == -1 ||\n                        score < best_score ||\n                        (score == best_score && (d < best_d ||\n                        (d == best_d && gain > best_gain)))) {\n                        best = v;\n                        best_score = score;\n                        best_d = d;\n                        best_gain = gain;\n                    }\n                }\n            }\n\n            if (best == -1) {\n                for (int v : nz_ids) if (!used[v]) { best = v; break; }\n            }\n\n            used[best] = 1;\n            seq.push_back(best);\n            load += val[best];\n            cur = best;\n        }\n        return seq;\n    }\n\n    void try_greedy_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        vector<int> lambdas = {2, 4, 8, 16, 32};\n        vector<int> starts = select_greedy_starts();\n\n        for (int lambda : lambdas) {\n            for (int st : starts) {\n                auto seq = build_greedy_linear(lambda, st);\n                consider_circle(seq);\n                reverse(seq.begin(), seq.end());\n                consider_circle(seq);\n            }\n        }\n    }\n\n    pair<int,int> farthest_pair(const vector<int>& nodes) const {\n        int a = nodes[0], b = nodes[0];\n        int best = -1;\n        for (int i = 0; i < (int)nodes.size(); ++i) {\n            for (int j = i + 1; j < (int)nodes.size(); ++j) {\n                int d = dist(nodes[i], nodes[j]);\n                if (d > best) {\n                    best = d;\n                    a = nodes[i];\n                    b = nodes[j];\n                }\n            }\n        }\n        return {a, b};\n    }\n\n    vector<int> build_nearest_neighbor_path(int start, int mode) const {\n        int K = (int)nz_ids.size();\n        vector<char> used(M, 0);\n        vector<int> seq;\n        seq.reserve(K);\n        seq.push_back(start);\n        used[start] = 1;\n\n        while ((int)seq.size() < K) {\n            int cur = seq.back();\n            int best = -1;\n            ll bestScore = INF64;\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                int d = dist(cur, v);\n                ll score;\n                if (mode == 0) score = d;\n                else if (mode == 1) score = 8LL * d - abs(val[v]);\n                else score = 16LL * d - 3LL * abs(val[v]);\n                if (best == -1 || score < bestScore ||\n                    (score == bestScore && d < dist(cur, best))) {\n                    best = v;\n                    bestScore = score;\n                }\n            }\n            used[best] = 1;\n            seq.push_back(best);\n        }\n        return seq;\n    }\n\n    vector<int> build_farthest_insertion_cycle(int mode) const {\n        int K = (int)nz_ids.size();\n        if (K <= 2) return nz_ids;\n\n        auto [a, b] = farthest_pair(nz_ids);\n        vector<int> cyc = {a, b};\n        vector<char> used(M, 0);\n        used[a] = used[b] = 1;\n\n        vector<int> nearest(M, 1e9);\n        for (int v : nz_ids) {\n            if (!used[v]) nearest[v] = min(dist(v, a), dist(v, b));\n        }\n\n        while ((int)cyc.size() < K) {\n            int pick = -1;\n            ll bestKey = -INF64;\n\n            for (int v : nz_ids) {\n                if (used[v]) continue;\n                ll key = (mode == 0 ? nearest[v] : 10LL * nearest[v] + abs(val[v]));\n                if (pick == -1 || key > bestKey) {\n                    pick = v;\n                    bestKey = key;\n                }\n            }\n\n            int L = (int)cyc.size();\n            int bestPos = 0;\n            ll bestDelta = INF64;\n            for (int i = 0; i < L; ++i) {\n                int x = cyc[i];\n                int y = cyc[(i + 1) % L];\n                ll delta = dist(x, pick) + dist(pick, y) - dist(x, y);\n                if (mode == 1) delta = 10LL * delta - abs(val[pick]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPos = i + 1;\n                }\n            }\n\n            cyc.insert(cyc.begin() + bestPos, pick);\n            used[pick] = 1;\n            for (int v : nz_ids) if (!used[v]) nearest[v] = min(nearest[v], dist(v, pick));\n        }\n        return cyc;\n    }\n\n    void try_tsp_like_orders() {\n        if (nz_ids.empty()) {\n            consider_circle({});\n            return;\n        }\n\n        auto fp = farthest_pair(nz_ids);\n        vector<int> starts = {fp.first, fp.second};\n\n        auto gs = select_greedy_starts();\n        for (int v : gs) if (v != -1) starts.push_back(v);\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n        if ((int)starts.size() > 12) starts.resize(12);\n\n        for (int st : starts) {\n            for (int mode = 0; mode < 3; ++mode) {\n                auto seq = build_nearest_neighbor_path(st, mode);\n                consider_circle(seq);\n                reverse(seq.begin(), seq.end());\n                consider_circle(seq);\n            }\n        }\n\n        for (int mode = 0; mode < 2; ++mode) {\n            auto cyc = build_farthest_insertion_cycle(mode);\n            consider_circle(cyc);\n            reverse(cyc.begin(), cyc.end());\n            consider_circle(cyc);\n        }\n    }\n\n    TreePlan build_tree_plan(int rr, int cc, int orient) const {\n        TreePlan tp;\n        tp.root = id(rr, cc);\n        tp.orient = orient;\n        tp.children.assign(M, {});\n        tp.parent.assign(M, -1);\n        tp.sum.assign(M, 0);\n        tp.sz.assign(M, 1);\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int v = id(r, c);\n                if (v == tp.root) continue;\n\n                int pr = r, pc = c;\n                if (orient == 0) {\n                    if (c != cc) pc += (c < cc ? 1 : -1);\n                    else pr += (r < rr ? 1 : -1);\n                } else {\n                    if (r != rr) pr += (r < rr ? 1 : -1);\n                    else pc += (c < cc ? 1 : -1);\n                }\n\n                int p = id(pr, pc);\n                tp.parent[v] = p;\n                tp.children[p].push_back(v);\n            }\n        }\n\n        function<void(int)> dfs = [&](int v) {\n            tp.sum[v] = val[v];\n            tp.sz[v] = 1;\n            for (int u : tp.children[v]) {\n                dfs(u);\n                tp.sum[v] += tp.sum[u];\n                tp.sz[v] += tp.sz[u];\n            }\n        };\n        dfs(tp.root);\n        return tp;\n    }\n\n    int choose_task(int v, const TreePlan &tp, const vector<int>& tasks,\n                    const vector<char>& used, ll cur_load) const {\n        auto get_delta = [&](int tk) -> ll {\n            if (tk == -1) return val[v];\n            return tp.sum[tk];\n        };\n        auto get_sz = [&](int tk) -> int {\n            if (tk == -1) return 0;\n            return tp.sz[tk];\n        };\n\n        int best_neg = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d >= 0) continue;\n            if (cur_load < -d) continue;\n\n            if (best_neg == -2) {\n                best_neg = i;\n            } else {\n                ll d1 = -get_delta(tasks[i]);\n                ll d2 = -get_delta(tasks[best_neg]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_neg]);\n                bool better = false;\n                if (s1 == 0 && s2 == 0) better = d1 > d2;\n                else if (s1 == 0) better = true;\n                else if (s2 == 0) better = false;\n                else {\n                    __int128 lhs = (__int128)d1 * s2;\n                    __int128 rhs = (__int128)d2 * s1;\n                    if (lhs != rhs) better = lhs > rhs;\n                    else better = d1 > d2;\n                }\n                if (better) best_neg = i;\n            }\n        }\n        if (best_neg != -2) return best_neg;\n\n        int best_pos = -2;\n        for (int i = 0; i < (int)tasks.size(); ++i) {\n            if (used[i]) continue;\n            ll d = get_delta(tasks[i]);\n            if (d < 0) continue;\n\n            if (best_pos == -2) {\n                best_pos = i;\n            } else {\n                ll p1 = get_delta(tasks[i]);\n                ll p2 = get_delta(tasks[best_pos]);\n                int s1 = get_sz(tasks[i]);\n                int s2 = get_sz(tasks[best_pos]);\n                bool better = false;\n                if (p1 == 0 && p2 > 0) better = true;\n                else if (p1 > 0 && p2 == 0) better = false;\n                else if (p1 == 0 && p2 == 0) better = false;\n                else {\n                    if (s1 == 0 && s2 == 0) better = p1 < p2;\n                    else if (s1 == 0) better = false;\n                    else if (s2 == 0) better = true;\n                    else {\n                        __int128 lhs = (__int128)p1 * s2;\n                        __int128 rhs = (__int128)p2 * s1;\n                        if (lhs != rhs) better = lhs < rhs;\n                        else better = p1 < p2;\n                    }\n                }\n                if (better) best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    struct EvalState {\n        ll load = 0;\n        ll loaded_move = 0;\n        bool ok = true;\n    };\n\n    void eval_tree_dfs(int v, const TreePlan &tp, EvalState &st) const {\n        if (!st.ok) return;\n\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, st.load);\n            if (idx < 0) {\n                st.ok = false;\n                return;\n            }\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                int hv = val[v];\n                if (hv < 0 && st.load < -1LL * hv) {\n                    st.ok = false;\n                    return;\n                }\n                st.load += hv;\n                if (st.load < 0) {\n                    st.ok = false;\n                    return;\n                }\n            } else {\n                if (tp.sum[tk] < 0 && st.load < -1LL * tp.sum[tk]) {\n                    st.ok = false;\n                    return;\n                }\n                st.loaded_move += st.load;\n                eval_tree_dfs(tk, tp, st);\n                if (!st.ok) return;\n                st.loaded_move += st.load;\n            }\n        }\n    }\n\n    ll eval_tree_plan(TreePlan &tp) const {\n        EvalState st;\n        eval_tree_dfs(tp.root, tp, st);\n        if (!st.ok || st.load != 0) return INF64;\n\n        auto [rr, cc] = rc(tp.root);\n        ll reposition = rr + cc;\n        ll moves = reposition + 2LL * (M - 1);\n        tp.var_cost = 100LL * moves + st.loaded_move;\n        return tp.var_cost;\n    }\n\n    void try_tree_family() {\n        for (int rr = 0; rr < N; ++rr) {\n            for (int cc = 0; cc < N; ++cc) {\n                for (int orient = 0; orient < 2; ++orient) {\n                    TreePlan tp = build_tree_plan(rr, cc, orient);\n                    ll var = eval_tree_plan(tp);\n                    if (var < best_var) {\n                        best_var = var;\n                        best_kind = 1;\n                        best_tree = move(tp);\n                    }\n                }\n            }\n        }\n    }\n\n    vector<int> op_insert(const vector<int>& seq, int i, int j) const {\n        vector<int> t = seq;\n        if (i == j) return t;\n        int x = t[i];\n        if (i < j) {\n            for (int p = i; p < j; ++p) t[p] = t[p + 1];\n            t[j] = x;\n        } else {\n            for (int p = i; p > j; --p) t[p] = t[p - 1];\n            t[j] = x;\n        }\n        return t;\n    }\n\n    vector<int> op_block_move(const vector<int>& seq, int l, int r, int pos) const {\n        vector<int> remain;\n        remain.reserve(seq.size());\n        vector<int> block;\n        block.reserve(r - l + 1);\n        for (int i = 0; i < (int)seq.size(); ++i) {\n            if (l <= i && i <= r) block.push_back(seq[i]);\n            else remain.push_back(seq[i]);\n        }\n        pos = min(pos, (int)remain.size());\n        vector<int> res;\n        res.reserve(seq.size());\n        for (int i = 0; i < pos; ++i) res.push_back(remain[i]);\n        for (int x : block) res.push_back(x);\n        for (int i = pos; i < (int)remain.size(); ++i) res.push_back(remain[i]);\n        return res;\n    }\n\n    void polish_adjacent(vector<int>& seq, ll& cur_cost,\n                         const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 1) return;\n\n        for (int pass = 0; pass < 3; ++pass) {\n            bool improved = false;\n            for (int i = 0; i + 1 < K; ++i) {\n                if ((i & 31) == 0 && time_over(end_time)) return;\n                swap(seq[i], seq[i + 1]);\n                EvalRes ev = eval_circle(seq);\n                if (ev.cost < cur_cost) {\n                    cur_cost = ev.cost;\n                    improved = true;\n                    update_best_circle(seq, ev);\n                } else {\n                    swap(seq[i], seq[i + 1]);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void polish_short_reverse(vector<int>& seq, ll& cur_cost, int W,\n                              const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 2) return;\n\n        for (int pass = 0; pass < 1; ++pass) {\n            bool improved = false;\n            for (int l = 0; l < K; ++l) {\n                if ((l & 15) == 0 && time_over(end_time)) return;\n                int rlim = min(K - 1, l + W);\n                ll best_here = cur_cost;\n                int best_r = -1;\n                for (int r = l + 1; r <= rlim; ++r) {\n                    vector<int> tmp = seq;\n                    reverse(tmp.begin() + l, tmp.begin() + r + 1);\n                    EvalRes ev = eval_circle(tmp);\n                    if (ev.cost < best_here) {\n                        best_here = ev.cost;\n                        best_r = r;\n                    }\n                }\n                if (best_r != -1) {\n                    reverse(seq.begin() + l, seq.begin() + best_r + 1);\n                    cur_cost = best_here;\n                    improved = true;\n                    EvalRes ev = eval_circle(seq);\n                    update_best_circle(seq, ev);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void polish_window_insert(vector<int>& seq, ll& cur_cost, int W,\n                              const chrono::steady_clock::time_point& end_time) {\n        int K = (int)seq.size();\n        if (K <= 1) return;\n\n        for (int pass = 0; pass < 1; ++pass) {\n            bool improved_any = false;\n            for (int i = 0; i < K; ++i) {\n                if ((i & 15) == 0 && time_over(end_time)) return;\n                ll best_here = cur_cost;\n                int best_j = i;\n                int L = max(0, i - W);\n                int R = min(K - 1, i + W);\n                for (int j = L; j <= R; ++j) {\n                    if (j == i) continue;\n                    auto tmp = op_insert(seq, i, j);\n                    EvalRes ev = eval_circle(tmp);\n                    if (ev.cost < best_here) {\n                        best_here = ev.cost;\n                        best_j = j;\n                    }\n                }\n                if (best_j != i) {\n                    seq = op_insert(seq, i, best_j);\n                    cur_cost = best_here;\n                    improved_any = true;\n                    EvalRes ev = eval_circle(seq);\n                    update_best_circle(seq, ev);\n                }\n            }\n            if (!improved_any) break;\n        }\n    }\n\n    void improve_seed(vector<int> seq,\n                      const chrono::steady_clock::time_point& end_time,\n                      mt19937& rng) {\n        int K = (int)seq.size();\n        if (K <= 1) {\n            EvalRes ev = eval_circle(seq);\n            update_best_circle(seq, ev);\n            return;\n        }\n\n        EvalRes cur_ev = eval_circle(seq);\n        ll cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        polish_adjacent(seq, cur_cost, end_time);\n        polish_short_reverse(seq, cur_cost, 8, end_time);\n        polish_window_insert(seq, cur_cost, 6, end_time);\n\n        cur_ev = eval_circle(seq);\n        cur_cost = cur_ev.cost;\n        update_best_circle(seq, cur_ev);\n\n        vector<int> best_local_seq = seq;\n        ll best_local_cost = cur_cost;\n\n        auto local_start = chrono::steady_clock::now();\n        uniform_real_distribution<double> urd(0.0, 1.0);\n\n        double T0 = 6000.0;\n        double T1 = 1.5;\n        double temp = T0;\n\n        uint64_t iter = 0;\n        while (!time_over(end_time)) {\n            if ((iter & 255ULL) == 0) {\n                auto now = chrono::steady_clock::now();\n                double elapsed = chrono::duration<double>(now - local_start).count();\n                double total = max(1e-6, chrono::duration<double>(end_time - local_start).count());\n                double prog = min(1.0, elapsed / total);\n                temp = T0 * pow(T1 / T0, prog);\n            }\n            ++iter;\n\n            vector<int> tmp = seq;\n            int type = (int)(rng() % 4);\n\n            if (type == 0) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                swap(tmp[i], tmp[j]);\n            } else if (type == 1) {\n                int i = (int)(rng() % K);\n                int span = 1 + (int)(rng() % 18);\n                int dir = (rng() & 1) ? 1 : -1;\n                int j = i + dir * span;\n                if (j < 0 || j >= K || i == j) continue;\n                tmp = op_insert(seq, i, j);\n            } else if (type == 2) {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 20);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                reverse(tmp.begin() + l, tmp.begin() + r + 1);\n            } else {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 8);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                int rem = K - (r - l + 1);\n                int pos = (int)(rng() % (rem + 1));\n                tmp = op_block_move(seq, l, r, pos);\n            }\n\n            EvalRes nev = eval_circle(tmp);\n            ll nv = nev.cost;\n            ll delta = nv - cur_cost;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-(double)delta / temp);\n                if (urd(rng) < prob) accept = true;\n            }\n\n            if (accept) {\n                seq.swap(tmp);\n                cur_cost = nv;\n                cur_ev = nev;\n                if (cur_cost < best_local_cost) {\n                    best_local_cost = cur_cost;\n                    best_local_seq = seq;\n                    update_best_circle(best_local_seq, cur_ev);\n                }\n            }\n\n            if ((iter & 1023ULL) == 0) {\n                polish_adjacent(seq, cur_cost, end_time);\n            }\n        }\n\n        seq = best_local_seq;\n        cur_cost = best_local_cost;\n        polish_adjacent(seq, cur_cost, end_time);\n        polish_short_reverse(seq, cur_cost, 8, end_time);\n        polish_window_insert(seq, cur_cost, 6, end_time);\n        EvalRes ev = eval_circle(seq);\n        update_best_circle(seq, ev);\n\n        for (int it = 0; it < 3000 && !time_over(end_time); ++it) {\n            vector<int> tmp = seq;\n            int type = (int)(rng() % 3);\n\n            if (type == 0) {\n                int i = (int)(rng() % K);\n                int j = (int)(rng() % K);\n                if (i == j) continue;\n                swap(tmp[i], tmp[j]);\n            } else if (type == 1) {\n                int i = (int)(rng() % K);\n                int span = 1 + (int)(rng() % 12);\n                int dir = (rng() & 1) ? 1 : -1;\n                int j = i + dir * span;\n                if (j < 0 || j >= K || i == j) continue;\n                tmp = op_insert(seq, i, j);\n            } else {\n                int l = (int)(rng() % K);\n                int len = 2 + (int)(rng() % 12);\n                int r = l + len - 1;\n                if (r >= K) continue;\n                reverse(tmp.begin() + l, tmp.begin() + r + 1);\n            }\n\n            EvalRes nev = eval_circle(tmp);\n            if (nev.cost < cur_cost) {\n                seq.swap(tmp);\n                cur_cost = nev.cost;\n                update_best_circle(seq, nev);\n            }\n        }\n    }\n\n    // ============================================================\n    // Diverse elite selection\n    // ============================================================\n    vector<int> circle_edge_signature(const vector<int>& seq) const {\n        int K = (int)seq.size();\n        vector<int> e;\n        e.reserve(K);\n        if (K == 0) return e;\n        for (int i = 0; i < K; ++i) {\n            int a = seq[i];\n            int b = seq[(i + 1) % K];\n            if (a > b) swap(a, b);\n            e.push_back(a * M + b);\n        }\n        sort(e.begin(), e.end());\n        e.erase(unique(e.begin(), e.end()), e.end());\n        return e;\n    }\n\n    int overlap_count(const vector<int>& a, const vector<int>& b) const {\n        int i = 0, j = 0, cnt = 0;\n        while (i < (int)a.size() && j < (int)b.size()) {\n            if (a[i] == b[j]) {\n                ++cnt; ++i; ++j;\n            } else if (a[i] < b[j]) {\n                ++i;\n            } else {\n                ++j;\n            }\n        }\n        return cnt;\n    }\n\n    vector<vector<int>> select_diverse_elites(int want) {\n        vector<vector<int>> res;\n        if (seed_pool.empty()) return res;\n\n        sort(seed_pool.begin(), seed_pool.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int C = min(20, (int)seed_pool.size());\n        vector<vector<int>> cand_seq(C);\n        vector<ll> cand_cost(C);\n        vector<vector<int>> sig(C);\n        for (int i = 0; i < C; ++i) {\n            cand_seq[i] = seed_pool[i].second;\n            cand_cost[i] = seed_pool[i].first;\n            sig[i] = circle_edge_signature(cand_seq[i]);\n        }\n\n        vector<int> chosen;\n        chosen.push_back(0);\n\n        while ((int)chosen.size() < min(want, C)) {\n            int best_idx = -1;\n            double best_key = 1e100;\n            ll best_cost = INF64;\n\n            for (int i = 0; i < C; ++i) {\n                bool used = false;\n                for (int x : chosen) if (x == i) { used = true; break; }\n                if (used) continue;\n\n                double sim = 0.0;\n                for (int x : chosen) {\n                    int ov = overlap_count(sig[i], sig[x]);\n                    int den = max(1, min((int)sig[i].size(), (int)sig[x].size()));\n                    sim = max(sim, (double)ov / den);\n                }\n\n                double norm = (double)(cand_cost[i] - cand_cost[0]) / max(1.0, (double)cand_cost[0]);\n                double key = sim + 6.0 * norm;\n\n                if (best_idx == -1 || key < best_key ||\n                    (fabs(key - best_key) < 1e-15 && cand_cost[i] < best_cost)) {\n                    best_idx = i;\n                    best_key = key;\n                    best_cost = cand_cost[i];\n                }\n            }\n\n            if (best_idx == -1) break;\n            chosen.push_back(best_idx);\n        }\n\n        for (int idx : chosen) res.push_back(cand_seq[idx]);\n        return res;\n    }\n\n    void improve_orders_by_local_search() {\n        if (seed_pool.empty()) return;\n\n        mt19937 rng(123456789);\n\n        auto reserve_tail = chrono::milliseconds(220);\n        auto phase1_end = global_deadline;\n        auto now0 = chrono::steady_clock::now();\n        if (now0 + reserve_tail < global_deadline) phase1_end = global_deadline - reserve_tail;\n\n        vector<vector<int>> elites = select_diverse_elites(3);\n\n        vector<double> w = {0.68, 0.22, 0.10};\n        for (int i = 0; i < (int)elites.size(); ++i) {\n            auto now = chrono::steady_clock::now();\n            if (now >= phase1_end) break;\n\n            long long rem_ns = chrono::duration_cast<chrono::nanoseconds>(phase1_end - now).count();\n            long long alloc_ns = (long long)(rem_ns * w[i]);\n            if (i + 1 == (int)elites.size()) alloc_ns = rem_ns;\n            alloc_ns = max<long long>(alloc_ns, 1LL);\n\n            auto local_end = min(phase1_end, now + chrono::nanoseconds(alloc_ns));\n            improve_seed(elites[i], local_end, rng);\n        }\n\n        while (chrono::steady_clock::now() < global_deadline && !best_circle.empty()) {\n            auto now = chrono::steady_clock::now();\n            auto rem = global_deadline - now;\n            auto rem_ms = chrono::duration_cast<chrono::milliseconds>(rem).count();\n            if (rem_ms <= 20) break;\n\n            int chunks = (rem_ms >= 120 ? 3 : 2);\n            auto chunk = rem / chunks;\n            auto end_time = min(global_deadline, now + chunk);\n            improve_seed(best_circle, end_time, rng);\n        }\n    }\n\n    // ============================================================\n    // Output\n    // ============================================================\n    void push_move_char(char ch) {\n        ans.emplace_back(1, ch);\n    }\n\n    void move_to(int tr, int tc) {\n        while (cur_r < tr) { push_move_char('D'); ++cur_r; }\n        while (cur_r > tr) { push_move_char('U'); --cur_r; }\n        while (cur_c < tc) { push_move_char('R'); ++cur_c; }\n        while (cur_c > tc) { push_move_char('L'); --cur_c; }\n    }\n\n    void move_to_id(int v) {\n        auto [r, c] = rc(v);\n        move_to(r, c);\n    }\n\n    void move_edge(int a, int b) {\n        auto [r1, c1] = rc(a);\n        auto [r2, c2] = rc(b);\n        if (r2 == r1 + 1 && c2 == c1) push_move_char('D');\n        else if (r2 == r1 - 1 && c2 == c1) push_move_char('U');\n        else if (r2 == r1 && c2 == c1 + 1) push_move_char('R');\n        else if (r2 == r1 && c2 == c1 - 1) push_move_char('L');\n        else assert(false);\n        cur_r = r2;\n        cur_c = c2;\n    }\n\n    void output_order_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        int K = (int)best_circle.size();\n        if (K == 0) return;\n\n        vector<int> ord;\n        ord.reserve(K);\n        for (int t = 0; t < K; ++t) ord.push_back(best_circle[(best_start + t) % K]);\n\n        move_to_id(ord[0]);\n\n        for (int i = 0; i < K; ++i) {\n            int v = ord[i];\n            auto [r, c] = rc(v);\n            assert(cur_r == r && cur_c == c);\n\n            if (val[v] > 0) {\n                ans.push_back(\"+\" + to_string(val[v]));\n                truck += val[v];\n            } else {\n                assert(truck >= -1LL * val[v]);\n                ans.push_back(\"-\" + to_string(-val[v]));\n                truck += val[v];\n            }\n\n            if (i + 1 < K) move_to_id(ord[i + 1]);\n        }\n        assert(truck == 0);\n    }\n\n    void output_tree_dfs(int v, const TreePlan &tp) {\n        vector<int> tasks = tp.children[v];\n        if (val[v] != 0) tasks.push_back(-1);\n\n        vector<char> used(tasks.size(), 0);\n        int rem = (int)tasks.size();\n\n        while (rem--) {\n            int idx = choose_task(v, tp, tasks, used, truck);\n            assert(idx >= 0);\n            used[idx] = 1;\n            int tk = tasks[idx];\n\n            if (tk == -1) {\n                if (val[v] > 0) {\n                    ans.push_back(\"+\" + to_string(val[v]));\n                    truck += val[v];\n                } else if (val[v] < 0) {\n                    assert(truck >= -1LL * val[v]);\n                    ans.push_back(\"-\" + to_string(-val[v]));\n                    truck += val[v];\n                }\n            } else {\n                move_edge(v, tk);\n                output_tree_dfs(tk, tp);\n                move_edge(tk, v);\n            }\n        }\n    }\n\n    void output_tree_solution() {\n        ans.clear();\n        truck = 0;\n        cur_r = 0;\n        cur_c = 0;\n\n        auto [rr, cc] = rc(best_tree.root);\n        move_to(rr, cc);\n        output_tree_dfs(best_tree.root, best_tree);\n        assert(truck == 0);\n    }\n\n    void solve() {\n        global_deadline = chrono::steady_clock::now() + chrono::milliseconds(1850);\n\n        try_geometric_orders();\n        try_projection_orders();\n        try_greedy_orders();\n        try_tsp_like_orders();\n\n        if (!time_over(global_deadline)) try_tree_family();\n        if (!time_over(global_deadline)) improve_orders_by_local_search();\n\n        if (best_kind == 1) output_tree_solution();\n        else output_order_solution();\n\n        assert((int)ans.size() <= 100000);\n        for (auto &s : ans) cout << s << '\\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>> h(N, vector<int>(N));\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) cin >> h[i][j];\n    }\n\n    Solver solver(N, h);\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463393265ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Solver {\n    int N, M, T, S;\n    vector<vector<int>> X;\n    vector<int> V;\n\n    vector<vector<int>> neighPos;\n    vector<pair<int,int>> edgesPos;\n    vector<int> posOrder;\n    vector<int> centers;\n\n    XorShift64 rng;\n\n    void build_grid() {\n        int P = N * N;\n        neighPos.assign(P, {});\n        edgesPos.clear();\n\n        auto id = [&](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 p = id(r, c);\n                if (r + 1 < N) {\n                    int q = id(r + 1, c);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n                if (c + 1 < N) {\n                    int q = id(r, c + 1);\n                    neighPos[p].push_back(q);\n                    neighPos[q].push_back(p);\n                    edgesPos.push_back({p, q});\n                }\n            }\n        }\n\n        vector<int> ps(P);\n        iota(ps.begin(), ps.end(), 0);\n\n        auto degree = [&](int p) { return (int)neighPos[p].size(); };\n        auto dist2_center = [&](int p) {\n            int r = p / N, c = p % N;\n            double cr = (N - 1) / 2.0;\n            double cc = (N - 1) / 2.0;\n            double dr = r - cr;\n            double dc = c - cc;\n            return dr * dr + dc * dc;\n        };\n\n        sort(ps.begin(), ps.end(), [&](int a, int b) {\n            int da = degree(a), db = degree(b);\n            if (da != db) return da > db;\n            double xa = dist2_center(a), xb = dist2_center(b);\n            if (xa != xb) return xa < xb;\n            return a < b;\n        });\n        posOrder = ps;\n\n        // Central 2x2 cells for N=6, but written generally.\n        int r0 = N / 2 - 1, r1 = N / 2;\n        int c0 = N / 2 - 1, c1 = N / 2;\n        centers = {id(r0, c0), id(r0, c1), id(r1, c0), id(r1, c1)};\n    }\n\n    bool read_seed_set() {\n        X.assign(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> X[i][j])) return false;\n            }\n        }\n        return true;\n    }\n\n    struct TurnInfo {\n        vector<double> rarityW;\n        vector<double> uniqBonus;\n        vector<double> weightedScore;\n        vector<double> partnerScore; // relative to eliteMain\n        int eliteMain;\n        int eliteBestV;\n    };\n\n    TurnInfo analyze_turn(int turn) {\n        TurnInfo info;\n        info.rarityW.assign(M, 1.0);\n        info.uniqBonus.assign(S, 0.0);\n        info.weightedScore.assign(S, 0.0);\n        info.partnerScore.assign(S, 0.0);\n\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> best1(M, -1), best2(M, -1), id1(M, -1);\n\n        for (int l = 0; l < M; l++) {\n            int b1 = -1, b2 = -1, who = -1;\n            for (int i = 0; i < S; i++) {\n                int v = X[i][l];\n                if (v > b1) {\n                    b2 = b1;\n                    b1 = v;\n                    who = i;\n                } else if (v > b2) {\n                    b2 = v;\n                }\n            }\n            best1[l] = b1;\n            best2[l] = max(0, b2);\n            id1[l] = who;\n\n            int gap = best1[l] - best2[l];\n            info.uniqBonus[who] += gap;\n\n            // Rare max coordinates should matter more, but keep weights bounded.\n            info.rarityW[l] = 1.0 + min(2.5, 0.06 * gap);\n        }\n\n        for (int i = 0; i < S; i++) {\n            double ws = 0.0;\n            for (int l = 0; l < M; l++) ws += info.rarityW[l] * X[i][l];\n            info.weightedScore[i] = ws;\n        }\n\n        // Main elite: blend total value + rarity preservation + weighted quality.\n        info.eliteBestV = max_element(V.begin(), V.end()) - V.begin();\n\n        double bestEliteScore = -1e100;\n        info.eliteMain = 0;\n        double uniqCoef = 0.7 + 0.9 * explore;\n        double wcoef = 0.10 + 0.10 * explore;\n        for (int i = 0; i < S; i++) {\n            double sc = V[i] + uniqCoef * info.uniqBonus[i] + wcoef * (info.weightedScore[i] - V[i]);\n            if (sc > bestEliteScore) {\n                bestEliteScore = sc;\n                info.eliteMain = i;\n            }\n        }\n\n        int e = info.eliteMain;\n        double riskCoef = 0.25 + 0.55 * (1.0 - explore);\n\n        for (int i = 0; i < S; i++) {\n            if (i == e) {\n                info.partnerScore[i] = -1e100;\n                continue;\n            }\n            double improve = 0.0, risk = 0.0;\n            for (int l = 0; l < M; l++) {\n                int a = X[i][l];\n                int b = X[e][l];\n                if (a > b) improve += info.rarityW[l] * (a - b);\n                else if (a < b) risk += info.rarityW[l] * (b - a);\n            }\n            info.partnerScore[i] = improve - riskCoef * risk + 0.12 * V[i];\n        }\n\n        return info;\n    }\n\n    vector<int> choose_seeds(int turn, const TurnInfo& info) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n        int P = N * N;\n\n        vector<char> used(S, 0);\n        vector<int> selected;\n\n        auto add_force = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Force main elite.\n        add_force(info.eliteMain);\n\n        // Force current best-by-total as well.\n        add_force(info.eliteBestV);\n\n        // Early: keep best seed of each criterion to avoid losing rare max values.\n        if (explore > 0.70) {\n            for (int l = 0; l < M; l++) {\n                int bestId = 0;\n                for (int i = 1; i < S; i++) {\n                    if (X[i][l] > X[bestId][l] ||\n                        (X[i][l] == X[bestId][l] && V[i] > V[bestId])) {\n                        bestId = i;\n                    }\n                }\n                add_force(bestId);\n            }\n        }\n\n        vector<double> candBonus(S, 0.0);\n\n        // Rankings.\n        vector<int> ordV(S), ordW(S), ordP(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        iota(ordW.begin(), ordW.end(), 0);\n        iota(ordP.begin(), ordP.end(), 0);\n\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n        sort(ordW.begin(), ordW.end(), [&](int a, int b) {\n            if (info.weightedScore[a] != info.weightedScore[b]) return info.weightedScore[a] > info.weightedScore[b];\n            return a < b;\n        });\n        sort(ordP.begin(), ordP.end(), [&](int a, int b) {\n            if (info.partnerScore[a] != info.partnerScore[b]) return info.partnerScore[a] > info.partnerScore[b];\n            return a < b;\n        });\n\n        int kTotal = 8 + (int)llround(6 * (1.0 - explore));\n        int kWeighted = 6 + (int)llround(4 * explore);\n        int kPartner = 6 + (int)llround(6 * (1.0 - explore));\n        int kCrit = (explore > 0.55 ? 2 : (explore > 0.20 ? 1 : 0));\n\n        for (int r = 0; r < min(kTotal, S); r++) candBonus[ordV[r]] += 40.0 - 2.0 * r;\n        for (int r = 0; r < min(kWeighted, S); r++) candBonus[ordW[r]] += 24.0 - 2.0 * r;\n        for (int r = 0; r < min(kPartner, S); r++) candBonus[ordP[r]] += 28.0 - 2.0 * r;\n\n        if (info.eliteMain >= 0) candBonus[info.eliteMain] += 40.0;\n        if (info.eliteBestV >= 0) candBonus[info.eliteBestV] += 20.0;\n\n        if (kCrit > 0) {\n            for (int l = 0; l < M; l++) {\n                vector<int> ids(S);\n                iota(ids.begin(), ids.end(), 0);\n                partial_sort(ids.begin(), ids.begin() + min(kCrit, S), ids.end(), [&](int a, int b) {\n                    if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                    return V[a] > V[b];\n                });\n                for (int r = 0; r < kCrit; r++) {\n                    candBonus[ids[r]] += (r == 0 ? 16.0 : 8.0) * info.rarityW[l];\n                }\n            }\n        }\n\n        vector<int> bestSel(M, 0);\n        for (int id : selected) {\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[id][l]);\n        }\n\n        double coverW = 0.65 * explore + 0.20;\n        double partnerW = 0.25 + 0.90 * (1.0 - explore);\n        double weightedExtraW = 0.10 + 0.20 * explore;\n        double uniqW = 0.15 + 0.15 * explore;\n\n        while ((int)selected.size() < P) {\n            double bestScore = -1e100;\n            int bestId = -1;\n\n            for (int i = 0; i < S; i++) if (!used[i]) {\n                double cov = 0.0;\n                for (int l = 0; l < M; l++) {\n                    if (X[i][l] > bestSel[l]) cov += info.rarityW[l] * (X[i][l] - bestSel[l]);\n                }\n\n                double sc =\n                    candBonus[i]\n                    + 1.00 * V[i]\n                    + coverW * cov\n                    + partnerW * max(0.0, info.partnerScore[i])\n                    + weightedExtraW * (info.weightedScore[i] - V[i])\n                    + uniqW * info.uniqBonus[i];\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            used[bestId] = 1;\n            selected.push_back(bestId);\n            for (int l = 0; l < M; l++) bestSel[l] = max(bestSel[l], X[bestId][l]);\n        }\n\n        return selected;\n    }\n\n    struct LayoutResult {\n        double score = -1e100;\n        vector<int> layoutGlobal;\n    };\n\n    double compute_pair_base(int ga, int gb, int turn) {\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        double mu = 0.5 * (V[ga] + V[gb]);\n\n        double sq = 0.0;\n        int diffCnt = 0;\n        int ub = 0;\n        for (int l = 0; l < M; l++) {\n            int d = X[ga][l] - X[gb][l];\n            sq += 1.0 * d * d;\n            if (d != 0) diffCnt++;\n            ub += max(X[ga][l], X[gb][l]);\n        }\n        double sigma = 0.5 * sqrt(sq);\n\n        // Immediate one-child quality approximation.\n        double q = mu + (0.55 + 0.20 * (1.0 - explore)) * sigma;\n\n        // Early turns: upper-bound potential matters more.\n        double gamma = 0.45 * explore;\n        double riskPenalty = (0.45 + 0.35 * (1.0 - explore)) * diffCnt;\n\n        return (1.0 - gamma) * q + gamma * (ub - riskPenalty);\n    }\n\n    double arrangement_score(\n        const vector<int>& perm,                  // position -> local seed\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,    // position adjacency multiplier\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        double sc = 0.0;\n        int P = N * N;\n        for (int p = 0; p < P; p++) {\n            sc += posCoef[p] * nodeVal[perm[p]];\n        }\n        for (auto [u, v] : edgesPos) {\n            sc += multMat[u][v] * pairBase[perm[u]][perm[v]];\n        }\n        return sc;\n    }\n\n    double delta_swap(\n        vector<int>& perm, int p, int q,\n        const vector<vector<double>>& pairBase,\n        const vector<vector<double>>& multMat,\n        const vector<double>& nodeVal,\n        const vector<int>& posCoef\n    ) {\n        if (p == q) return 0.0;\n\n        array<pair<int,int>, 8> aff{};\n        int cnt = 0;\n\n        auto add_edge = [&](int a, int b) {\n            if (a > b) swap(a, b);\n            for (int i = 0; i < cnt; i++) {\n                if (aff[i].first == a && aff[i].second == b) return;\n            }\n            aff[cnt++] = {a, b};\n        };\n\n        for (int nb : neighPos[p]) add_edge(p, nb);\n        for (int nb : neighPos[q]) add_edge(q, nb);\n\n        double oldv = 0.0, newv = 0.0;\n\n        oldv += posCoef[p] * nodeVal[perm[p]] + posCoef[q] * nodeVal[perm[q]];\n        newv += posCoef[p] * nodeVal[perm[q]] + posCoef[q] * nodeVal[perm[p]];\n\n        auto get_seed_after = [&](int pos) -> int {\n            if (pos == p) return perm[q];\n            if (pos == q) return perm[p];\n            return perm[pos];\n        };\n\n        for (int i = 0; i < cnt; i++) {\n            auto [a, b] = aff[i];\n            oldv += multMat[a][b] * pairBase[perm[a]][perm[b]];\n            newv += multMat[a][b] * pairBase[get_seed_after(a)][get_seed_after(b)];\n        }\n\n        return newv - oldv;\n    }\n\n    LayoutResult optimize_layout(const vector<int>& selected, const TurnInfo& info, int turn) {\n        int P = N * N;\n        double explore = (T <= 1 ? 0.0 : (double)(T - 1 - turn) / (T - 1));\n\n        vector<int> localToGlobal = selected;\n        vector<int> globalToLocal(S, -1);\n        for (int i = 0; i < P; i++) globalToLocal[localToGlobal[i]] = i;\n\n        vector<vector<double>> pairBase(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                double w = compute_pair_base(localToGlobal[i], localToGlobal[j], turn);\n                pairBase[i][j] = pairBase[j][i] = w;\n            }\n        }\n\n        vector<double> nodeVal(P, 0.0);\n        for (int i = 0; i < P; i++) {\n            int g = localToGlobal[i];\n            nodeVal[i] =\n                0.12 * V[g]\n                + 0.18 * max(0.0, info.partnerScore[g])\n                + 0.08 * info.uniqBonus[g]\n                + 0.04 * (info.weightedScore[g] - V[g]);\n        }\n\n        vector<int> posCoef(P, 0);\n        for (int p = 0; p < P; p++) {\n            posCoef[p] = (int)neighPos[p].size() - 2; // corner 0, border 1, interior 2\n        }\n\n        vector<int> eliteCandidates;\n        if (globalToLocal[info.eliteMain] != -1) eliteCandidates.push_back(info.eliteMain);\n        if (info.eliteBestV != info.eliteMain && globalToLocal[info.eliteBestV] != -1) {\n            eliteCandidates.push_back(info.eliteBestV);\n        }\n        if (eliteCandidates.empty()) eliteCandidates.push_back(localToGlobal[0]);\n\n        LayoutResult best;\n\n        for (int eliteGlobal : eliteCandidates) {\n            int eliteLocal = globalToLocal[eliteGlobal];\n            if (eliteLocal < 0) continue;\n\n            for (int hubPos : centers) {\n                double hubBoost = 0.55 + 0.55 * (1.0 - explore);\n\n                vector<vector<double>> multMat(P, vector<double>(P, 0.0));\n                for (auto [u, v] : edgesPos) {\n                    double mul = 1.0 + ((u == hubPos || v == hubPos) ? hubBoost : 0.0);\n                    multMat[u][v] = multMat[v][u] = mul;\n                }\n\n                vector<int> perm(P, -1);\n                vector<char> usedLocal(P, 0);\n\n                perm[hubPos] = eliteLocal;\n                usedLocal[eliteLocal] = 1;\n\n                // Put good elite partners around the hub first.\n                vector<int> around = neighPos[hubPos];\n                vector<int> remSeeds;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) remSeeds.push_back(i);\n\n                sort(remSeeds.begin(), remSeeds.end(), [&](int a, int b) {\n                    int ga = localToGlobal[a], gb = localToGlobal[b];\n                    double sa =\n                        0.75 * max(0.0, info.partnerScore[ga]) +\n                        0.40 * V[ga] +\n                        0.10 * info.weightedScore[ga];\n                    double sb =\n                        0.75 * max(0.0, info.partnerScore[gb]) +\n                        0.40 * V[gb] +\n                        0.10 * info.weightedScore[gb];\n                    if (sa != sb) return sa > sb;\n                    return ga < gb;\n                });\n\n                int ptr = 0;\n                for (int p : around) {\n                    while (ptr < (int)remSeeds.size() && usedLocal[remSeeds[ptr]]) ptr++;\n                    if (ptr < (int)remSeeds.size()) {\n                        perm[p] = remSeeds[ptr];\n                        usedLocal[remSeeds[ptr]] = 1;\n                        ptr++;\n                    }\n                }\n\n                // Fill remaining positions by general node score.\n                vector<int> posFill;\n                for (int p : posOrder) {\n                    if (perm[p] == -1) posFill.push_back(p);\n                }\n\n                vector<int> seedFill;\n                for (int i = 0; i < P; i++) if (!usedLocal[i]) seedFill.push_back(i);\n\n                sort(seedFill.begin(), seedFill.end(), [&](int a, int b) {\n                    if (nodeVal[a] != nodeVal[b]) return nodeVal[a] > nodeVal[b];\n                    return localToGlobal[a] < localToGlobal[b];\n                });\n\n                for (int k = 0; k < (int)posFill.size(); k++) {\n                    perm[posFill[k]] = seedFill[k];\n                }\n\n                double cur = arrangement_score(perm, pairBase, multMat, nodeVal, posCoef);\n\n                // SA / hill-climb with elite fixed at hub.\n                vector<char> fixed(P, 0);\n                fixed[hubPos] = 1;\n\n                int ITER = 9000;\n                double T0 = 18.0;\n                double T1 = 0.15;\n\n                for (int it = 0; it < ITER; it++) {\n                    int p = rng.next_int(P);\n                    int q = rng.next_int(P);\n                    if (p == q || fixed[p] || fixed[q]) continue;\n\n                    double temp = T0 * pow(T1 / T0, (double)it / ITER);\n                    double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n\n                    if (d >= 0.0 || rng.next_double() < exp(d / temp)) {\n                        swap(perm[p], perm[q]);\n                        cur += d;\n                    }\n                }\n\n                // Final hill-climb.\n                for (int rep = 0; rep < 12; rep++) {\n                    double bestDelta = 1e-12;\n                    int bp = -1, bq = -1;\n                    for (int p = 0; p < P; p++) if (!fixed[p]) {\n                        for (int q = p + 1; q < P; q++) if (!fixed[q]) {\n                            double d = delta_swap(perm, p, q, pairBase, multMat, nodeVal, posCoef);\n                            if (d > bestDelta) {\n                                bestDelta = d;\n                                bp = p;\n                                bq = q;\n                            }\n                        }\n                    }\n                    if (bp == -1) break;\n                    swap(perm[bp], perm[bq]);\n                    cur += bestDelta;\n                }\n\n                if (cur > best.score) {\n                    best.score = cur;\n                    best.layoutGlobal.assign(P, -1);\n                    for (int p = 0; p < P; p++) {\n                        best.layoutGlobal[p] = localToGlobal[perm[p]];\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> T;\n        S = 2 * N * (N - 1);\n\n        build_grid();\n        if (!read_seed_set()) return;\n\n        for (int turn = 0; turn < T; turn++) {\n            V.assign(S, 0);\n            for (int i = 0; i < S; i++) {\n                for (int l = 0; l < M; l++) V[i] += X[i][l];\n            }\n\n            TurnInfo info = analyze_turn(turn);\n            vector<int> selected = choose_seeds(turn, info);\n            LayoutResult res = optimize_layout(selected, info, turn);\n            vector<int> layout = res.layoutGlobal;\n\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    if (c) cout << ' ';\n                    cout << layout[r * N + c];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (!read_seed_set()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\nstatic inline bool operator==(const Pt& a, const Pt& b) {\n    return a.x == b.x && a.y == b.y;\n}\n\nstatic const int DX[4] = {0, 1, 0, -1}; // R, D, L, U\nstatic const int DY[4] = {1, 0, -1, 0};\n\nstruct Goal {\n    bool ok = false;\n    int leaf = -1;\n    int dir = -1;\n    Pt rootPos{-1, -1};\n    Pt cell{-1, -1};\n    int cost = INT_MAX;\n    int md = INT_MAX;\n    int rd = INT_MAX;\n};\n\nstruct Problem {\n    int N, M, Vmax;\n    vector<string> s, t;\n\n    vector<Pt> surplusCells, deficitCells;\n    vector<vector<int>> sid, did;\n\n    Pt clamp(Pt p) const {\n        p.x = max(0, min(N - 1, p.x));\n        p.y = max(0, min(N - 1, p.y));\n        return p;\n    }\n\n    Pt centroid(const vector<Pt>& v) const {\n        if (v.empty()) return {N / 2, N / 2};\n        long long sx = 0, sy = 0;\n        for (auto &p : v) sx += p.x, sy += p.y;\n        return clamp({(int)llround((double)sx / (int)v.size()),\n                      (int)llround((double)sy / (int)v.size())});\n    }\n\n    Pt midpoint(Pt a, Pt b) const {\n        return clamp({(a.x + b.x) / 2, (a.y + b.y) / 2});\n    }\n\n    Pt medianAll() const {\n        vector<int> xs, ys;\n        xs.reserve(surplusCells.size() + deficitCells.size());\n        ys.reserve(surplusCells.size() + deficitCells.size());\n        for (auto &p : surplusCells) xs.push_back(p.x), ys.push_back(p.y);\n        for (auto &p : deficitCells) xs.push_back(p.x), ys.push_back(p.y);\n        if (xs.empty()) return {N / 2, N / 2};\n        nth_element(xs.begin(), xs.begin() + xs.size() / 2, xs.end());\n        nth_element(ys.begin(), ys.begin() + ys.size() / 2, ys.end());\n        return clamp({xs[xs.size() / 2], ys[ys.size() / 2]});\n    }\n\n    Pt centroidAll() const {\n        vector<Pt> all = surplusCells;\n        all.insert(all.end(), deficitCells.begin(), deficitCells.end());\n        return centroid(all);\n    }\n\n    Pt center() const {\n        return {N / 2, N / 2};\n    }\n\n    Pt centroidSurplus() const {\n        return centroid(surplusCells);\n    }\n\n    Pt centroidDeficit() const {\n        return centroid(deficitCells);\n    }\n\n    Pt midpointSD() const {\n        return midpoint(centroidSurplus(), centroidDeficit());\n    }\n\n    Pt midpointMC() const {\n        return midpoint(medianAll(), centroidAll());\n    }\n\n    Pt midpointCenterCentroid() const {\n        return midpoint(center(), centroidAll());\n    }\n\n    Pt midpointCenterMedian() const {\n        return midpoint(center(), medianAll());\n    }\n\n    Pt midpointAllSurplus() const {\n        return midpoint(centroidAll(), centroidSurplus());\n    }\n\n    Pt midpointAllDeficit() const {\n        return midpoint(centroidAll(), centroidDeficit());\n    }\n\n    Pt midpointCenterSurplus() const {\n        return midpoint(center(), centroidSurplus());\n    }\n\n    Pt midpointCenterDeficit() const {\n        return midpoint(center(), centroidDeficit());\n    }\n};\n\nstruct SimResult {\n    bool complete = false;\n    int turns = (int)1e9;\n    Pt initialRoot{0, 0};\n    vector<int> len;\n    vector<string> ops;\n};\n\nstruct Simulator {\n    const Problem& P;\n\n    int N, K, Vp;\n    vector<int> len;\n\n    Pt initialRoot, root;\n    vector<int> dirLeaf;\n    vector<char> holding;\n    int holdCnt = 0;\n\n    vector<char> aliveS, aliveD;\n    int remS = 0, remD = 0;\n\n    vector<string> ops;\n    int cutoffTurns;\n\n    Simulator(const Problem& prob, const vector<int>& lengths, Pt rootInit, int cutoff)\n        : P(prob), N(prob.N), K((int)lengths.size() - 1), Vp((int)lengths.size()),\n          len(lengths), initialRoot(rootInit), root(rootInit), cutoffTurns(cutoff)\n    {\n        dirLeaf.assign(Vp, 0);\n        holding.assign(Vp, false);\n        aliveS.assign(P.surplusCells.size(), true);\n        aliveD.assign(P.deficitCells.size(), true);\n        remS = (int)P.surplusCells.size();\n        remD = (int)P.deficitCells.size();\n    }\n\n    inline bool inb(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    inline int rotDist(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        return min(d, 4 - d);\n    }\n\n    inline int applyRot(int cur, char c) const {\n        if (c == 'L') return (cur + 3) & 3;\n        if (c == 'R') return (cur + 1) & 3;\n        return cur;\n    }\n\n    inline char oneStepRotToward(int cur, int des) const {\n        int d = (des - cur + 4) % 4;\n        if (d == 0) return '.';\n        if (d == 1) return 'R';\n        if (d == 3) return 'L';\n        return 'L';\n    }\n\n    inline Pt moveRoot(Pt p, char mv) const {\n        if (mv == 'U') p.x--;\n        else if (mv == 'D') p.x++;\n        else if (mv == 'L') p.y--;\n        else if (mv == 'R') p.y++;\n        return p;\n    }\n\n    inline bool isSurplusCell(int x, int y) const {\n        int id = P.sid[x][y];\n        return (id != -1 && aliveS[id]);\n    }\n\n    inline bool isDeficitCell(int x, int y) const {\n        int id = P.did[x][y];\n        return (id != -1 && aliveD[id]);\n    }\n\n    pair<bool, Pt> remainingCentroid(bool deficit) const {\n        long long sx = 0, sy = 0;\n        int cnt = 0;\n        if (deficit) {\n            for (int i = 0; i < (int)P.deficitCells.size(); i++) if (aliveD[i]) {\n                sx += P.deficitCells[i].x;\n                sy += P.deficitCells[i].y;\n                cnt++;\n            }\n        } else {\n            for (int i = 0; i < (int)P.surplusCells.size(); i++) if (aliveS[i]) {\n                sx += P.surplusCells[i].x;\n                sy += P.surplusCells[i].y;\n                cnt++;\n            }\n        }\n        if (cnt == 0) return {false, {0, 0}};\n        return {true, {(int)llround((double)sx / cnt), (int)llround((double)sy / cnt)}};\n    }\n\n    Goal findGoal(bool wantDrop) const {\n        Goal best;\n        if (wantDrop) {\n            if (holdCnt == 0 || remD == 0) return best;\n            for (int id = 0; id < (int)P.deficitCells.size(); id++) {\n                if (!aliveD[id]) continue;\n                const Pt& c = P.deficitCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (!holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        } else {\n            if (holdCnt == K || remS == 0) return best;\n            for (int id = 0; id < (int)P.surplusCells.size(); id++) {\n                if (!aliveS[id]) continue;\n                const Pt& c = P.surplusCells[id];\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (holding[leaf]) continue;\n                    int d = len[leaf];\n                    for (int dir = 0; dir < 4; dir++) {\n                        int px = c.x - DX[dir] * d;\n                        int py = c.y - DY[dir] * d;\n                        if (!inb(px, py)) continue;\n                        int md = abs(root.x - px) + abs(root.y - py);\n                        int rd = rotDist(dirLeaf[leaf], dir);\n                        int cost = max(md, rd);\n                        if (!best.ok ||\n                            cost < best.cost ||\n                            (cost == best.cost && md < best.md) ||\n                            (cost == best.cost && md == best.md && rd < best.rd)) {\n                            best.ok = true;\n                            best.leaf = leaf;\n                            best.dir = dir;\n                            best.rootPos = {px, py};\n                            best.cell = c;\n                            best.cost = cost;\n                            best.md = md;\n                            best.rd = rd;\n                        }\n                    }\n                }\n            }\n        }\n        return best;\n    }\n\n    bool chooseMode(const Goal& gp, const Goal& gd) const {\n        if (remD == 0 && holdCnt > 0) return true;\n        if (holdCnt == 0) return false;\n        if (holdCnt == K) return true;\n        if (!gd.ok) return false;\n        if (!gp.ok) return true;\n\n        if (holdCnt * 2 < K) {\n            if (gd.cost + 2 < gp.cost) return true;\n            return false;\n        } else {\n            if (gp.cost + 2 < gd.cost) return false;\n            return true;\n        }\n    }\n\n    struct MatchResult {\n        int cnt = 0;\n        int priSum = 0;\n        vector<char> rot;\n        vector<char> act;\n        MatchResult() {}\n        MatchResult(int Vp): rot(Vp, '.'), act(Vp, '.') {}\n    };\n\n    struct EdgeCand {\n        int leaf;\n        int cellIdx;\n        char rot;\n        int ndir;\n        int pri;\n    };\n\n    struct MCMFEdge {\n        int to, rev, cap, cost;\n    };\n\n    void add_edge(vector<vector<MCMFEdge>>& g, int fr, int to, int cap, int cost) const {\n        g[fr].push_back(MCMFEdge{to, (int)g[to].size(), cap, cost});\n        g[to].push_back(MCMFEdge{fr, (int)g[fr].size() - 1, 0, -cost});\n    }\n\n    MatchResult buildMatching(Pt newRoot, bool wantDrop, const Goal* prefGoal) const {\n        MatchResult res(Vp);\n\n        vector<Pt> cells;\n        vector<EdgeCand> cands;\n        vector<vector<int>> candIdxByLeaf(Vp);\n\n        auto getCellIdx = [&](int x, int y) {\n            for (int i = 0; i < (int)cells.size(); i++) {\n                if (cells[i].x == x && cells[i].y == y) return i;\n            }\n            cells.push_back({x, y});\n            return (int)cells.size() - 1;\n        };\n\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (wantDrop && !holding[leaf]) continue;\n            if (!wantDrop && holding[leaf]) continue;\n\n            vector<pair<int, EdgeCand>> tmp;\n            for (auto [rc, delta] : vector<pair<char,int>>{{'.',0},{'L',-1},{'R',+1}}) {\n                int nd = dirLeaf[leaf];\n                if (delta == -1) nd = (nd + 3) & 3;\n                else if (delta == +1) nd = (nd + 1) & 3;\n\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                if (!inb(x, y)) continue;\n\n                bool ok = wantDrop ? isDeficitCell(x, y) : isSurplusCell(x, y);\n                if (!ok) continue;\n\n                int pri = 0;\n                if (prefGoal && prefGoal->ok &&\n                    prefGoal->leaf == leaf &&\n                    prefGoal->dir == nd &&\n                    prefGoal->rootPos == newRoot &&\n                    prefGoal->cell.x == x && prefGoal->cell.y == y) {\n                    pri += 100;\n                }\n                pri += (rc == '.' ? 2 : 1);\n\n                int ci = getCellIdx(x, y);\n                EdgeCand e{leaf, ci, rc, nd, pri};\n\n                bool found = false;\n                for (auto &pe : tmp) {\n                    if (pe.first == ci) {\n                        if (e.pri > pe.second.pri) pe.second = e;\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) tmp.push_back({ci, e});\n            }\n\n            for (auto &pe : tmp) {\n                int idx = (int)cands.size();\n                cands.push_back(pe.second);\n                candIdxByLeaf[leaf].push_back(idx);\n            }\n        }\n\n        if (cands.empty()) return res;\n\n        vector<int> usedLeafs;\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (!candIdxByLeaf[leaf].empty()) usedLeafs.push_back(leaf);\n        }\n\n        int L = (int)usedLeafs.size();\n        int C = (int)cells.size();\n\n        vector<int> leafNode(Vp, -1);\n        for (int i = 0; i < L; i++) leafNode[usedLeafs[i]] = 1 + i;\n        int cellBase = 1 + L;\n        int SRC = 0;\n        int SNK = cellBase + C;\n        int V = SNK + 1;\n\n        vector<vector<MCMFEdge>> g(V);\n\n        for (int leaf : usedLeafs) add_edge(g, SRC, leafNode[leaf], 1, 0);\n        for (int ci = 0; ci < C; ci++) add_edge(g, cellBase + ci, SNK, 1, 0);\n\n        const int BASE = 10000;\n        struct Ref {\n            int leaf;\n            int edgePos;\n            int pri;\n            char rot;\n        };\n        vector<Ref> refs;\n\n        for (int idx = 0; idx < (int)cands.size(); idx++) {\n            auto &e = cands[idx];\n            int u = leafNode[e.leaf];\n            int v = cellBase + e.cellIdx;\n            int pos = (int)g[u].size();\n            add_edge(g, u, v, 1, -(BASE + e.pri));\n            refs.push_back({e.leaf, pos, e.pri, e.rot});\n        }\n\n        while (true) {\n            const int INF = 1e9;\n            vector<int> dist(V, INF), pv(V, -1), pe(V, -1);\n            vector<char> inq(V, false);\n            queue<int> q;\n            dist[SRC] = 0;\n            q.push(SRC);\n            inq[SRC] = true;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                inq[v] = false;\n                for (int i = 0; i < (int)g[v].size(); i++) {\n                    auto &e = g[v][i];\n                    if (e.cap <= 0) continue;\n                    int nd = dist[v] + e.cost;\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        if (!inq[e.to]) {\n                            inq[e.to] = true;\n                            q.push(e.to);\n                        }\n                    }\n                }\n            }\n\n            if (dist[SNK] == INF || dist[SNK] >= 0) break;\n\n            int v = SNK;\n            while (v != SRC) {\n                auto &e = g[pv[v]][pe[v]];\n                e.cap -= 1;\n                g[v][e.rev].cap += 1;\n                v = pv[v];\n            }\n        }\n\n        for (auto &r : refs) {\n            auto &e = g[leafNode[r.leaf]][r.edgePos];\n            if (e.cap == 0) {\n                res.cnt++;\n                res.priSum += r.pri;\n                res.rot[r.leaf] = r.rot;\n                res.act[r.leaf] = 'P';\n            }\n        }\n        return res;\n    }\n\n    long long evaluateMove(\n        char mv,\n        const Goal& gp,\n        const Goal& gd,\n        bool preferDrop,\n        bool hasCD, Pt cenD,\n        bool hasCS, Pt cenS,\n        MatchResult* outDrop,\n        MatchResult* outPick\n    ) const {\n        Pt nr = moveRoot(root, mv);\n        MatchResult dropRes = buildMatching(nr, true, preferDrop ? &gd : nullptr);\n        MatchResult pickRes = buildMatching(nr, false, preferDrop ? nullptr : &gp);\n\n        int primaryCnt = preferDrop ? dropRes.cnt : pickRes.cnt;\n        int secondaryCnt = preferDrop ? pickRes.cnt : dropRes.cnt;\n        int primaryPri = preferDrop ? dropRes.priSum : pickRes.priSum;\n        int secondaryPri = preferDrop ? pickRes.priSum : dropRes.priSum;\n\n        const Goal& mainGoal = preferDrop ? gd : gp;\n        const Goal& subGoal  = preferDrop ? gp : gd;\n\n        long long score = 0;\n        score += 1LL * primaryCnt * 1000000;\n        score += 1LL * secondaryCnt * 20000;\n        score += 1LL * primaryPri * 200;\n        score += 1LL * secondaryPri * 20;\n\n        if (mainGoal.ok) {\n            int d = abs(nr.x - mainGoal.rootPos.x) + abs(nr.y - mainGoal.rootPos.y);\n            score -= 100LL * d;\n        } else if (subGoal.ok) {\n            int d = abs(nr.x - subGoal.rootPos.x) + abs(nr.y - subGoal.rootPos.y);\n            score -= 100LL * d;\n        }\n\n        if (primaryCnt + secondaryCnt == 0) {\n            if (preferDrop && hasCD) {\n                score -= 8LL * (abs(nr.x - cenD.x) + abs(nr.y - cenD.y));\n            } else if (!preferDrop && hasCS) {\n                score -= 8LL * (abs(nr.x - cenS.x) + abs(nr.y - cenS.y));\n            }\n        }\n\n        if (mv == '.' && (primaryCnt + secondaryCnt) > 0) score += 5;\n\n        if (outDrop) *outDrop = std::move(dropRes);\n        if (outPick) *outPick = std::move(pickRes);\n        return score;\n    }\n\n    void appendCommand(char mv, const vector<char>& rot, const vector<char>& act) {\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        for (int i = 1; i <= K; i++) {\n            cmd[i] = rot[i];\n            cmd[Vp + i] = act[i];\n        }\n        ops.push_back(cmd);\n    }\n\n    char chooseSimpleMoveToward(Pt goalPos) const {\n        int dx = goalPos.x - root.x;\n        int dy = goalPos.y - root.y;\n        if (abs(dx) >= abs(dy)) {\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n        } else {\n            if (dy > 0) return 'R';\n            if (dy < 0) return 'L';\n            if (dx > 0) return 'D';\n            if (dx < 0) return 'U';\n        }\n        return '.';\n    }\n\n    bool actOneGoal(const Goal& g, bool wantDrop) {\n        int leaf = g.leaf;\n        while (true) {\n            if ((int)ops.size() >= 100000 || (int)ops.size() >= cutoffTurns) return false;\n\n            char mv = chooseSimpleMoveToward(g.rootPos);\n            char rc = oneStepRotToward(dirLeaf[leaf], g.dir);\n\n            Pt nr = moveRoot(root, mv);\n            int nd = applyRot(dirLeaf[leaf], rc);\n            bool canAct = (nr == g.rootPos && nd == g.dir);\n\n            vector<char> rot(Vp, '.');\n            vector<char> act(Vp, '.');\n            rot[leaf] = rc;\n            if (canAct) act[leaf] = 'P';\n\n            appendCommand(mv, rot, act);\n\n            root = nr;\n            dirLeaf[leaf] = nd;\n\n            if (canAct) {\n                if (wantDrop) {\n                    int id = P.did[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveD[id] && holding[leaf]) {\n                        aliveD[id] = false;\n                        remD--;\n                        holding[leaf] = false;\n                        holdCnt--;\n                        return true;\n                    }\n                } else {\n                    int id = P.sid[g.cell.x][g.cell.y];\n                    if (id != -1 && aliveS[id] && !holding[leaf]) {\n                        aliveS[id] = false;\n                        remS--;\n                        holding[leaf] = true;\n                        holdCnt++;\n                        return true;\n                    }\n                }\n                return false;\n            }\n        }\n    }\n\n    void steerIdleLeaves(\n        Pt newRoot,\n        vector<char>& rot,\n        vector<char>& act,\n        bool hasCD, Pt cenD,\n        bool hasCS, Pt cenS\n    ) const {\n        for (int leaf = 1; leaf <= K; leaf++) {\n            if (act[leaf] != '.') continue;\n            if (rot[leaf] != '.') continue;\n\n            bool wantDrop = holding[leaf];\n            if (wantDrop && !hasCD) continue;\n            if (!wantDrop && !hasCS) continue;\n            Pt target = wantDrop ? cenD : cenS;\n\n            int cur = dirLeaf[leaf];\n            vector<pair<char,int>> opts = {{'.', cur}, {'L', (cur + 3) & 3}, {'R', (cur + 1) & 3}};\n\n            int bestVal = INT_MAX;\n            char bestRot = '.';\n            for (auto [rc, nd] : opts) {\n                int x = newRoot.x + DX[nd] * len[leaf];\n                int y = newRoot.y + DY[nd] * len[leaf];\n                int val = abs(x - target.x) + abs(y - target.y);\n                if (rc != '.') val += 1;\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestRot = rc;\n                }\n            }\n            rot[leaf] = bestRot;\n        }\n    }\n\n    int breakerScore(const Goal& g, bool wantDrop) const {\n        if (!g.ok) return INT_MAX / 4;\n        int score = g.cost * 32 + g.md * 2 + g.rd;\n\n        if (wantDrop) {\n            if (holdCnt * 2 < K) score += 12;\n            if (remD <= K) score -= 8;\n            if (remD <= 2) score -= 8;\n        } else {\n            if (holdCnt * 2 >= K) score += 12;\n            if (remS <= K) score -= 8;\n            if (remS <= 2) score -= 8;\n        }\n        return score;\n    }\n\n    int stallLimit() const {\n        int lim = 4 * N + 40;\n        if (holdCnt == 0 || holdCnt == K) lim = min(lim, 3 * N + 22);\n        if (remD <= K || remS <= K) lim = min(lim, 2 * N + 18);\n        if (remD + remS <= 2 * K) lim = min(lim, 2 * N + 10);\n        return lim;\n    }\n\n    SimResult run() {\n        while ((remD > 0 || holdCnt > 0) &&\n               (int)ops.size() < 100000 &&\n               (int)ops.size() < cutoffTurns)\n        {\n            int noActionStreak = 0;\n\n            while ((remD > 0 || holdCnt > 0) &&\n                   (int)ops.size() < 100000 &&\n                   (int)ops.size() < cutoffTurns)\n            {\n                Goal gp = findGoal(false);\n                Goal gd = findGoal(true);\n                if (!gp.ok && !gd.ok) break;\n\n                bool preferDrop = chooseMode(gp, gd);\n                auto [hasCD, cenD] = remainingCentroid(true);\n                auto [hasCS, cenS] = remainingCentroid(false);\n\n                vector<char> legalMoves = {'.', 'U', 'D', 'L', 'R'};\n                long long bestScore = LLONG_MIN;\n                char bestMv = '.';\n                MatchResult bestDrop(Vp), bestPick(Vp);\n\n                for (char mv : legalMoves) {\n                    Pt nr = moveRoot(root, mv);\n                    if (!inb(nr.x, nr.y)) continue;\n\n                    MatchResult dr(Vp), pr(Vp);\n                    long long sc = evaluateMove(mv, gp, gd, preferDrop, hasCD, cenD, hasCS, cenS, &dr, &pr);\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestMv = mv;\n                        bestDrop = std::move(dr);\n                        bestPick = std::move(pr);\n                    }\n                }\n\n                Pt newRoot = moveRoot(root, bestMv);\n                vector<char> rot(Vp, '.');\n                vector<char> act(Vp, '.');\n\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (bestDrop.act[leaf] == 'P') {\n                        rot[leaf] = bestDrop.rot[leaf];\n                        act[leaf] = 'P';\n                    }\n                }\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (act[leaf] == '.' && bestPick.act[leaf] == 'P') {\n                        rot[leaf] = bestPick.rot[leaf];\n                        act[leaf] = 'P';\n                    }\n                }\n\n                const Goal& mainGoal = preferDrop ? gd : gp;\n                if (mainGoal.ok && act[mainGoal.leaf] == '.') {\n                    rot[mainGoal.leaf] = oneStepRotToward(dirLeaf[mainGoal.leaf], mainGoal.dir);\n                }\n\n                steerIdleLeaves(newRoot, rot, act, hasCD, cenD, hasCS, cenS);\n\n                appendCommand(bestMv, rot, act);\n\n                bool didAction = false;\n                root = newRoot;\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    dirLeaf[leaf] = applyRot(dirLeaf[leaf], rot[leaf]);\n                }\n\n                for (int leaf = 1; leaf <= K; leaf++) {\n                    if (act[leaf] != 'P') continue;\n                    int x = root.x + DX[dirLeaf[leaf]] * len[leaf];\n                    int y = root.y + DY[dirLeaf[leaf]] * len[leaf];\n                    if (!inb(x, y)) continue;\n\n                    if (holding[leaf]) {\n                        int id = P.did[x][y];\n                        if (id != -1 && aliveD[id]) {\n                            aliveD[id] = false;\n                            remD--;\n                            holding[leaf] = false;\n                            holdCnt--;\n                            didAction = true;\n                        }\n                    } else {\n                        int id = P.sid[x][y];\n                        if (id != -1 && aliveS[id]) {\n                            aliveS[id] = false;\n                            remS--;\n                            holding[leaf] = true;\n                            holdCnt++;\n                            didAction = true;\n                        }\n                    }\n                }\n\n                if (didAction) noActionStreak = 0;\n                else noActionStreak++;\n\n                if (noActionStreak > stallLimit()) break;\n            }\n\n            if (remD == 0 && holdCnt == 0) break;\n            if ((int)ops.size() >= 100000 || (int)ops.size() >= cutoffTurns) break;\n\n            Goal gp = findGoal(false);\n            Goal gd = findGoal(true);\n            if (!gp.ok && !gd.ok) break;\n\n            bool tryDropFirst = breakerScore(gd, true) <= breakerScore(gp, false);\n\n            bool ok = false;\n            if (tryDropFirst && gd.ok) ok = actOneGoal(gd, true);\n            else if (!tryDropFirst && gp.ok) ok = actOneGoal(gp, false);\n\n            if (!ok) {\n                if (tryDropFirst && gp.ok) ok = actOneGoal(gp, false);\n                else if (!tryDropFirst && gd.ok) ok = actOneGoal(gd, true);\n            }\n\n            if (!ok) break;\n        }\n\n        SimResult res;\n        res.initialRoot = initialRoot;\n        res.len = len;\n        res.ops = ops;\n        res.complete = (remD == 0 && holdCnt == 0);\n        res.turns = res.complete ? (int)ops.size() : (int)1e9;\n        return res;\n    }\n};\n\nstatic vector<vector<int>> generateDesigns(int K, int N) {\n    vector<vector<int>> designs;\n    auto add = [&](vector<int> a) {\n        if ((int)a.size() != K + 1) return;\n        for (int i = 1; i <= K; i++) a[i] = max(1, min(N - 1, a[i]));\n        for (auto &b : designs) if (b == a) return;\n        designs.push_back(a);\n    };\n\n    // Uniform stars\n    for (int L = 1; L <= min(7, N - 1); L++) {\n        vector<int> a(K + 1, L);\n        a[0] = 0;\n        add(a);\n    }\n\n    // Cyclic short/medium\n    for (int R : {2, 3, 4, 5}) {\n        R = max(1, min(R, N - 1));\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) % R;\n        add(a);\n    }\n\n    // Cyclic medium/long\n    {\n        vector<int> a(K + 1, 2);\n        a[0] = 0;\n        int R = max(2, min(5, N - 1));\n        for (int i = 1; i <= K; i++) a[i] = min(N - 1, 2 + (i - 1) % max(1, R - 1));\n        add(a);\n    }\n    {\n        int hi = min(6, N - 1);\n        if (hi >= 3) {\n            vector<int> a(K + 1, 3);\n            a[0] = 0;\n            int span = hi - 2; // cycle 3..hi\n            for (int i = 1; i <= K; i++) a[i] = 3 + (i - 1) % span;\n            add(a);\n        }\n    }\n\n    // Paired 1,1,2,2,...\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = 1 + (i - 1) / 2;\n        add(a);\n    }\n\n    // Distinct 1,2,3,...\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        for (int i = 1; i <= K; i++) a[i] = i;\n        add(a);\n    }\n\n    // Mostly short, a few long\n    {\n        vector<int> a(K + 1, 1);\n        a[0] = 0;\n        if (K >= 1) a[K] = min(N - 1, 2);\n        if (K >= 2) a[K - 1] = min(N - 1, 3);\n        if (K >= 3) a[K - 2] = min(N - 1, 4);\n        if (K >= 4) a[K - 3] = min(N - 1, 5);\n        add(a);\n    }\n\n    // Mostly long, a few short\n    {\n        int base = min(5, N - 1);\n        vector<int> a(K + 1, base);\n        a[0] = 0;\n        if (K >= 1) a[1] = 1;\n        if (K >= 2) a[2] = min(N - 1, 2);\n        if (K >= 3) a[3] = min(N - 1, 3);\n        if (K >= 4) a[4] = min(N - 1, 4);\n        add(a);\n    }\n\n    return designs;\n}\n\nstatic vector<Pt> generateRoots(const Problem& P) {\n    vector<Pt> roots;\n    auto add = [&](Pt p) {\n        p = P.clamp(p);\n        for (auto &q : roots) if (q == p) return;\n        roots.push_back(p);\n    };\n\n    add(P.medianAll());\n    add(P.centroidAll());\n    add(P.center());\n    add(P.centroidSurplus());\n    add(P.centroidDeficit());\n    add(P.midpointSD());\n    add(P.midpointMC());\n    add(P.midpointCenterCentroid());\n    add(P.midpointCenterMedian());\n    add(P.midpointAllSurplus());\n    add(P.midpointAllDeficit());\n    add(P.midpointCenterSurplus());\n    add(P.midpointCenterDeficit());\n\n    return roots;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem P;\n    cin >> P.N >> P.M >> P.Vmax;\n    P.s.resize(P.N);\n    P.t.resize(P.N);\n    for (int i = 0; i < P.N; i++) cin >> P.s[i];\n    for (int i = 0; i < P.N; i++) cin >> P.t[i];\n\n    P.sid.assign(P.N, vector<int>(P.N, -1));\n    P.did.assign(P.N, vector<int>(P.N, -1));\n\n    for (int i = 0; i < P.N; i++) {\n        for (int j = 0; j < P.N; j++) {\n            if (P.s[i][j] == '1' && P.t[i][j] == '0') {\n                P.sid[i][j] = (int)P.surplusCells.size();\n                P.surplusCells.push_back({i, j});\n            }\n            if (P.s[i][j] == '0' && P.t[i][j] == '1') {\n                P.did[i][j] = (int)P.deficitCells.size();\n                P.deficitCells.push_back({i, j});\n            }\n        }\n    }\n\n    int K = P.Vmax - 1;\n    auto designs = generateDesigns(K, P.N);\n    auto roots = generateRoots(P);\n\n    auto root_static_score = [&](const Pt& r) -> long long {\n        long long s = 0;\n        for (auto &p : P.surplusCells) s += abs(r.x - p.x) + abs(r.y - p.y);\n        for (auto &p : P.deficitCells) s += abs(r.x - p.x) + abs(r.y - p.y);\n        return s;\n    };\n    stable_sort(roots.begin(), roots.end(), [&](const Pt& a, const Pt& b) {\n        return root_static_score(a) < root_static_score(b);\n    });\n\n    SimResult best;\n    int cutoff = 1000000000;\n\n    for (const auto& root : roots) {\n        for (const auto& len : designs) {\n            Simulator sim(P, len, root, cutoff);\n            SimResult cur = sim.run();\n            if (cur.complete && cur.turns < best.turns) {\n                best = std::move(cur);\n                cutoff = best.turns;\n            }\n        }\n    }\n\n    if (!best.complete) {\n        Simulator sim(P, designs[0], roots[0], 1000000000);\n        best = sim.run();\n    }\n\n    int Vp = K + 1;\n    cout << Vp << '\\n';\n    for (int i = 1; i <= K; i++) {\n        cout << 0 << ' ' << best.len[i] << '\\n';\n    }\n    cout << best.initialRoot.x << ' ' << best.initialRoot.y << '\\n';\n    for (const string& cmd : best.ops) {\n        cout << cmd << '\\n';\n    }\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Point {\n    int x, y;\n};\n\nstruct WPoint {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Candidate {\n    vector<Point> poly;\n    int approx = INT_MIN / 4;\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    bool over(double limit_ms) const {\n        return elapsed_ms() > limit_ms;\n    }\n};\n\nstatic inline uint64_t pack_xy(int x, int y) {\n    return (uint64_t(uint32_t(x)) << 32) | uint32_t(y);\n}\n\nstatic inline bool on_segment(const Point& p, const Point& a, const Point& b) {\n    if (a.x == b.x) {\n        if (p.x != a.x) return false;\n        return min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);\n    } else if (a.y == b.y) {\n        if (p.y != a.y) return false;\n        return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x);\n    }\n    return false;\n}\n\nstatic bool inside_polygon_inclusive(const Point& p, const vector<Point>& poly) {\n    bool in = false;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        Point a = poly[i];\n        Point b = poly[(i + 1) % n];\n\n        if (on_segment(p, a, b)) return true;\n\n        if (a.x == b.x) {\n            if (a.y > b.y) swap(a, b);\n            if (a.y <= p.y && p.y < b.y && p.x < a.x) {\n                in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int exact_diff(const vector<Point>& poly, const vector<WPoint>& pts) {\n    if (poly.empty()) return INT_MIN / 4;\n\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    for (auto &q : poly) {\n        minx = min(minx, q.x);\n        maxx = max(maxx, q.x);\n        miny = min(miny, q.y);\n        maxy = max(maxy, q.y);\n    }\n\n    int diff = 0;\n    for (auto &pt : pts) {\n        if (pt.x < minx || pt.x > maxx || pt.y < miny || pt.y > maxy) continue;\n        if (inside_polygon_inclusive(Point{pt.x, pt.y}, poly)) diff += pt.w;\n    }\n    return diff;\n}\n\nstatic long long polygon_perimeter(const vector<Point>& poly) {\n    long long per = 0;\n    int n = (int)poly.size();\n    for (int i = 0; i < n; i++) {\n        const auto &a = poly[i];\n        const auto &b = poly[(i + 1) % n];\n        per += llabs((long long)a.x - b.x) + llabs((long long)a.y - b.y);\n    }\n    return per;\n}\n\nstatic bool legal_polygon(const vector<Point>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    if (polygon_perimeter(poly) > 400000LL) return false;\n    set<pair<int,int>> st;\n    for (auto &p : poly) {\n        if (p.x < 0 || p.x > 100000 || p.y < 0 || p.y > 100000) return false;\n        if (!st.insert({p.x, p.y}).second) return false;\n    }\n    return true;\n}\n\nstatic vector<Point> fallback_polygon(const unordered_set<uint64_t>& occ) {\n    for (int x = 0; x <= 200; x++) {\n        for (int y = 0; y <= 200; y++) {\n            if (!occ.count(pack_xy(x, y)) &&\n                !occ.count(pack_xy(x + 1, y)) &&\n                !occ.count(pack_xy(x, y + 1)) &&\n                !occ.count(pack_xy(x + 1, y + 1))) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nstatic vector<int> build_lines(int S, int offset) {\n    vector<int> v;\n    v.push_back(0);\n    for (int x = offset; x < 100000; x += S) {\n        if (x > 0) v.push_back(x);\n    }\n    if (v.back() != 100000) v.push_back(100000);\n    sort(v.begin(), v.end());\n    v.erase(unique(v.begin(), v.end()), v.end());\n    return v;\n}\n\nstatic int find_cell(const vector<int>& lines, int coord) {\n    int idx = int(upper_bound(lines.begin(), lines.end(), coord) - lines.begin()) - 1;\n    if (idx < 0) idx = 0;\n    if (idx >= (int)lines.size() - 1) idx = (int)lines.size() - 2;\n    return idx;\n}\n\nstatic vector<char> solve_selection_by_cut(const vector<int>& cell_w, int W, int H, int lambda) {\n    if (lambda == 0) {\n        vector<char> sel(W * H, 0);\n        for (int i = 0; i < W * H; i++) if (cell_w[i] > 0) sel[i] = 1;\n        return sel;\n    }\n\n    int SRC = W * H;\n    int SNK = W * H + 1;\n    mf_graph<int> g(W * H + 2);\n\n    auto id = [&](int x, int y) -> int { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int outside_sides = 0;\n            if (x == 0) outside_sides++;\n            if (x == W - 1) outside_sides++;\n            if (y == 0) outside_sides++;\n            if (y == H - 1) outside_sides++;\n\n            int u = cell_w[v] - lambda * outside_sides;\n            if (u >= 0) g.add_edge(SRC, v, u);\n            else g.add_edge(v, SNK, -u);\n\n            if (x + 1 < W) {\n                int to = id(x + 1, y);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n            if (y + 1 < H) {\n                int to = id(x, y + 1);\n                g.add_edge(v, to, lambda);\n                g.add_edge(to, v, lambda);\n            }\n        }\n    }\n\n    g.flow(SRC, SNK);\n    auto cut = g.min_cut(SRC);\n\n    vector<char> sel(W * H, 0);\n    for (int i = 0; i < W * H; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nstatic void fill_holes(vector<char>& sel, int W, int H) {\n    vector<char> vis(W * H, 0);\n    queue<int> q;\n\n    auto push_if = [&](int x, int y) {\n        int id = y * W + x;\n        if (!sel[id] && !vis[id]) {\n            vis[id] = 1;\n            q.push(id);\n        }\n    };\n\n    for (int x = 0; x < W; x++) {\n        push_if(x, 0);\n        push_if(x, H - 1);\n    }\n    for (int y = 0; y < H; y++) {\n        push_if(0, y);\n        push_if(W - 1, y);\n    }\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        int x = v % W, y = v / W;\n        for (int d = 0; d < 4; d++) {\n            int nx = x + dx[d], ny = y + dy[d];\n            if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n            int nid = ny * W + nx;\n            if (!sel[nid] && !vis[nid]) {\n                vis[nid] = 1;\n                q.push(nid);\n            }\n        }\n    }\n\n    for (int i = 0; i < W * H; i++) {\n        if (!sel[i] && !vis[i]) sel[i] = 1;\n    }\n}\n\nstatic void cleanup_selection(vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int iter = 0; iter < 2; iter++) {\n        vector<char> nxt = sel;\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int id = y * W + x;\n                int cnt = 0;\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + dx[d], ny = y + dy[d];\n                    if (0 <= nx && nx < W && 0 <= ny && ny < H) cnt += sel[ny * W + nx];\n                }\n                if (sel[id]) {\n                    if (cnt <= 1 && cell_w[id] <= 0) nxt[id] = 0;\n                } else {\n                    if (cnt >= 3 && cell_w[id] > 0) nxt[id] = 1;\n                }\n            }\n        }\n        sel.swap(nxt);\n    }\n}\n\nstruct Component {\n    vector<int> cells;\n    int approx = 0;\n    int minx = INT_MAX, maxx = INT_MIN;\n    int miny = INT_MAX, maxy = INT_MIN;\n};\n\nstatic vector<Component> get_components(const vector<char>& sel, const vector<int>& cell_w, int W, int H) {\n    vector<char> vis(W * H, 0);\n    vector<Component> comps;\n    queue<int> q;\n\n    const int dx[4] = {1, -1, 0, 0};\n    const int dy[4] = {0, 0, 1, -1};\n\n    for (int s = 0; s < W * H; s++) {\n        if (!sel[s] || vis[s]) continue;\n        vis[s] = 1;\n        q.push(s);\n\n        Component comp;\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            comp.cells.push_back(v);\n            comp.approx += cell_w[v];\n\n            int x = v % W, y = v / W;\n            comp.minx = min(comp.minx, x);\n            comp.maxx = max(comp.maxx, x);\n            comp.miny = min(comp.miny, y);\n            comp.maxy = max(comp.maxy, y);\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir];\n                int ny = y + dy[dir];\n                if (nx < 0 || nx >= W || ny < 0 || ny >= H) continue;\n                int nid = ny * W + nx;\n                if (sel[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        comps.push_back(move(comp));\n    }\n\n    sort(comps.begin(), comps.end(), [](const Component& a, const Component& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        return a.cells.size() > b.cells.size();\n    });\n    return comps;\n}\n\nstruct PolyInfo {\n    vector<Point> poly;\n    bool ok = false;\n};\n\nstatic PolyInfo build_polygon_from_component(\n    const vector<char>& comp_sel, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    PolyInfo res;\n    int GW = W + 1;\n    int GV = (W + 1) * (H + 1);\n    vector<int> nxt(GV, -1);\n    int edge_cnt = 0;\n\n    auto vid = [&](int x, int y) -> int { return y * GW + x; };\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) -> bool {\n        int a = vid(x1, y1);\n        int b = vid(x2, y2);\n        if (nxt[a] != -1) return false;\n        nxt[a] = b;\n        edge_cnt++;\n        return true;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int id = y * W + x;\n            if (!comp_sel[id]) continue;\n\n            if (y == 0 || !comp_sel[(y - 1) * W + x]) {\n                if (!add_edge(x, y, x + 1, y)) return res;\n            }\n            if (x == W - 1 || !comp_sel[y * W + (x + 1)]) {\n                if (!add_edge(x + 1, y, x + 1, y + 1)) return res;\n            }\n            if (y == H - 1 || !comp_sel[(y + 1) * W + x]) {\n                if (!add_edge(x + 1, y + 1, x, y + 1)) return res;\n            }\n            if (x == 0 || !comp_sel[y * W + (x - 1)]) {\n                if (!add_edge(x, y + 1, x, y)) return res;\n            }\n        }\n    }\n\n    if (edge_cnt == 0) return res;\n\n    int start = -1;\n    for (int i = 0; i < GV; i++) {\n        if (nxt[i] != -1) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return res;\n\n    vector<int> cyc;\n    int cur = start;\n    for (int step = 0; step <= edge_cnt + 5; step++) {\n        cyc.push_back(cur);\n        cur = nxt[cur];\n        if (cur == -1) return res;\n        if (cur == start) break;\n    }\n    if (cur != start) return res;\n    if ((int)cyc.size() != edge_cnt) return res;\n\n    auto dec = [&](int v) -> pair<int,int> { return {v % GW, v / GW}; };\n    auto dir = [&](int a, int b) -> pair<int,int> {\n        auto [x1, y1] = dec(a);\n        auto [x2, y2] = dec(b);\n        return {(x2 > x1) - (x2 < x1), (y2 > y1) - (y2 < y1)};\n    };\n\n    vector<Point> poly;\n    int n = (int)cyc.size();\n    for (int i = 0; i < n; i++) {\n        int pv = cyc[(i - 1 + n) % n];\n        int cv = cyc[i];\n        int nv = cyc[(i + 1) % n];\n        if (dir(pv, cv) != dir(cv, nv)) {\n            auto [gx, gy] = dec(cv);\n            poly.push_back({xs[gx], ys[gy]});\n        }\n    }\n\n    if ((int)poly.size() < 4) return res;\n    res.poly = move(poly);\n    res.ok = true;\n    return res;\n}\n\nstatic Candidate max_sum_rectangle_candidate(\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    vector<int> acc(H);\n\n    for (int l = 0; l < W; l++) {\n        fill(acc.begin(), acc.end(), 0);\n        for (int r = l; r < W; r++) {\n            for (int y = 0; y < H; y++) acc[y] += cell_w[y * W + r];\n\n            int cur = 0, st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = acc[y];\n                    st = y;\n                } else {\n                    cur += acc[y];\n                }\n                if (cur > best.approx) {\n                    int x1 = xs[l], x2 = xs[r + 1];\n                    int y1 = ys[st], y2 = ys[y + 1];\n                    if (x1 < x2 && y1 < y2) {\n                        vector<Point> poly = {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}};\n                        if (legal_polygon(poly)) {\n                            best.approx = cur;\n                            best.poly = move(poly);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\nstatic int nearest_cell_in_component(const Component& c, int tx, int ty, int W) {\n    int best = -1;\n    int bestd = INT_MAX;\n    for (int v : c.cells) {\n        int x = v % W;\n        int y = v / W;\n        int d = abs(x - tx) + abs(y - ty);\n        if (d < bestd) {\n            bestd = d;\n            best = v;\n        }\n    }\n    return best;\n}\n\nstatic Candidate connect_top2_components_candidate(\n    const vector<Component>& comps,\n    const vector<int>& cell_w, int W, int H,\n    const vector<int>& xs, const vector<int>& ys\n) {\n    Candidate best;\n    if ((int)comps.size() < 2) return best;\n\n    const Component& A = comps[0];\n    const Component& B = comps[1];\n\n    int txA, txB;\n    if (A.maxx < B.minx) {\n        txA = A.maxx;\n        txB = B.minx;\n    } else if (B.maxx < A.minx) {\n        txA = A.minx;\n        txB = B.maxx;\n    } else {\n        txA = txB = (max(A.minx, B.minx) + min(A.maxx, B.maxx)) / 2;\n    }\n\n    int tyA, tyB;\n    if (A.maxy < B.miny) {\n        tyA = A.maxy;\n        tyB = B.miny;\n    } else if (B.maxy < A.miny) {\n        tyA = A.miny;\n        tyB = B.maxy;\n    } else {\n        tyA = tyB = (max(A.miny, B.miny) + min(A.maxy, B.maxy)) / 2;\n    }\n\n    int va = nearest_cell_in_component(A, txA, tyA, W);\n    int vb = nearest_cell_in_component(B, txB, tyB, W);\n    if (va < 0 || vb < 0) return best;\n\n    int ax = va % W, ay = va / W;\n    int bx = vb % W, by = vb / W;\n\n    for (int mode = 0; mode < 2; mode++) {\n        vector<char> sel(W * H, 0);\n        int approx = 0;\n\n        auto add_cell = [&](int x, int y) {\n            if (x < 0 || x >= W || y < 0 || y >= H) return;\n            int id = y * W + x;\n            if (!sel[id]) {\n                sel[id] = 1;\n                approx += cell_w[id];\n            }\n        };\n\n        for (int v : A.cells) if (!sel[v]) { sel[v] = 1; approx += cell_w[v]; }\n        for (int v : B.cells) if (!sel[v]) { sel[v] = 1; approx += cell_w[v]; }\n\n        if (mode == 0) {\n            if (ax <= bx) for (int x = ax; x <= bx; x++) add_cell(x, ay);\n            else for (int x = ax; x >= bx; x--) add_cell(x, ay);\n            if (ay <= by) for (int y = ay; y <= by; y++) add_cell(bx, y);\n            else for (int y = ay; y >= by; y--) add_cell(bx, y);\n        } else {\n            if (ay <= by) for (int y = ay; y <= by; y++) add_cell(ax, y);\n            else for (int y = ay; y >= by; y--) add_cell(ax, y);\n            if (ax <= bx) for (int x = ax; x <= bx; x++) add_cell(x, by);\n            else for (int x = ax; x >= bx; x--) add_cell(x, by);\n        }\n\n        fill_holes(sel, W, H);\n        PolyInfo info = build_polygon_from_component(sel, W, H, xs, ys);\n        if (!info.ok) continue;\n        if (!legal_polygon(info.poly)) continue;\n\n        if (approx > best.approx) {\n            best.approx = approx;\n            best.poly = move(info.poly);\n        }\n    }\n\n    return best;\n}\n\nstatic vector<Point> build_rect_poly(int x1, int y1, int x2, int y2) {\n    return {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}};\n}\n\nstatic bool extract_rectangle(const vector<Point>& poly, int& x1, int& y1, int& x2, int& y2) {\n    if ((int)poly.size() != 4) return false;\n    int minx = poly[0].x, maxx = poly[0].x;\n    int miny = poly[0].y, maxy = poly[0].y;\n    set<pair<int,int>> st;\n    for (auto &p : poly) {\n        minx = min(minx, p.x);\n        maxx = max(maxx, p.x);\n        miny = min(miny, p.y);\n        maxy = max(maxy, p.y);\n        st.insert({p.x, p.y});\n    }\n    if (minx >= maxx || miny >= maxy) return false;\n    if ((int)st.size() != 4) return false;\n    if (!st.count({minx, miny})) return false;\n    if (!st.count({maxx, miny})) return false;\n    if (!st.count({maxx, maxy})) return false;\n    if (!st.count({minx, maxy})) return false;\n    x1 = minx; y1 = miny; x2 = maxx; y2 = maxy;\n    return true;\n}\n\nstatic int optimize_left_edge(int y1, int y2, int x2, const vector<WPoint>& pts) {\n    vector<pair<int,int>> arr;\n    arr.reserve(pts.size());\n    int total = 0;\n    for (auto &p : pts) {\n        if (y1 <= p.y && p.y <= y2 && p.x <= x2) {\n            arr.push_back({p.x, p.w});\n            total += p.w;\n        }\n    }\n    sort(arr.begin(), arr.end());\n\n    int bestScore = total;\n    int bestX = 0;\n    int removed = 0;\n\n    for (int i = 0; i < (int)arr.size();) {\n        int x = arr[i].first;\n        int sw = 0;\n        while (i < (int)arr.size() && arr[i].first == x) {\n            sw += arr[i].second;\n            i++;\n        }\n        if (x >= x2) break;\n        removed += sw;\n        int candX = min(x + 1, x2 - 1);\n        int candScore = total - removed;\n        if (candX < x2 && (candScore > bestScore || (candScore == bestScore && candX > bestX))) {\n            bestScore = candScore;\n            bestX = candX;\n        }\n    }\n\n    int candX = x2 - 1;\n    if (candX >= 0) {\n        int candScore = total - removed;\n        if (candScore > bestScore || (candScore == bestScore && candX > bestX)) {\n            bestScore = candScore;\n            bestX = candX;\n        }\n    }\n    return bestX;\n}\n\nstatic int optimize_right_edge(int x1, int y1, int y2, const vector<WPoint>& pts) {\n    vector<pair<int,int>> arr;\n    arr.reserve(pts.size());\n    for (auto &p : pts) {\n        if (y1 <= p.y && p.y <= y2 && p.x >= x1) arr.push_back({p.x, p.w});\n    }\n    sort(arr.begin(), arr.end());\n\n    int minX2 = x1 + 1;\n    int cur = 0;\n    int i = 0;\n    while (i < (int)arr.size() && arr[i].first <= minX2) {\n        int x = arr[i].first, sw = 0;\n        while (i < (int)arr.size() && arr[i].first == x) {\n            sw += arr[i].second;\n            i++;\n        }\n        cur += sw;\n    }\n\n    int bestScore = cur;\n    int bestX = minX2;\n\n    while (i < (int)arr.size()) {\n        int x = arr[i].first, sw = 0;\n        while (i < (int)arr.size() && arr[i].first == x) {\n            sw += arr[i].second;\n            i++;\n        }\n        cur += sw;\n        int candX = x;\n        if (candX <= x1) continue;\n        int candScore = cur;\n        if (candScore > bestScore || (candScore == bestScore && candX < bestX)) {\n            bestScore = candScore;\n            bestX = candX;\n        }\n    }\n\n    if (bestX > 100000) bestX = 100000;\n    if (bestX <= x1) bestX = x1 + 1;\n    return bestX;\n}\n\nstatic int optimize_bottom_edge(int x1, int x2, int y2, const vector<WPoint>& pts) {\n    vector<pair<int,int>> arr;\n    arr.reserve(pts.size());\n    int total = 0;\n    for (auto &p : pts) {\n        if (x1 <= p.x && p.x <= x2 && p.y <= y2) {\n            arr.push_back({p.y, p.w});\n            total += p.w;\n        }\n    }\n    sort(arr.begin(), arr.end());\n\n    int bestScore = total;\n    int bestY = 0;\n    int removed = 0;\n\n    for (int i = 0; i < (int)arr.size();) {\n        int y = arr[i].first, sw = 0;\n        while (i < (int)arr.size() && arr[i].first == y) {\n            sw += arr[i].second;\n            i++;\n        }\n        if (y >= y2) break;\n        removed += sw;\n        int candY = min(y + 1, y2 - 1);\n        int candScore = total - removed;\n        if (candY < y2 && (candScore > bestScore || (candScore == bestScore && candY > bestY))) {\n            bestScore = candScore;\n            bestY = candY;\n        }\n    }\n\n    int candY = y2 - 1;\n    if (candY >= 0) {\n        int candScore = total - removed;\n        if (candScore > bestScore || (candScore == bestScore && candY > bestY)) {\n            bestScore = candScore;\n            bestY = candY;\n        }\n    }\n    return bestY;\n}\n\nstatic int optimize_top_edge(int x1, int x2, int y1, const vector<WPoint>& pts) {\n    vector<pair<int,int>> arr;\n    arr.reserve(pts.size());\n    for (auto &p : pts) {\n        if (x1 <= p.x && p.x <= x2 && p.y >= y1) arr.push_back({p.y, p.w});\n    }\n    sort(arr.begin(), arr.end());\n\n    int minY2 = y1 + 1;\n    int cur = 0;\n    int i = 0;\n    while (i < (int)arr.size() && arr[i].first <= minY2) {\n        int y = arr[i].first, sw = 0;\n        while (i < (int)arr.size() && arr[i].first == y) {\n            sw += arr[i].second;\n            i++;\n        }\n        cur += sw;\n    }\n\n    int bestScore = cur;\n    int bestY = minY2;\n\n    while (i < (int)arr.size()) {\n        int y = arr[i].first, sw = 0;\n        while (i < (int)arr.size() && arr[i].first == y) {\n            sw += arr[i].second;\n            i++;\n        }\n        cur += sw;\n        int candY = y;\n        if (candY <= y1) continue;\n        int candScore = cur;\n        if (candScore > bestScore || (candScore == bestScore && candY < bestY)) {\n            bestScore = candScore;\n            bestY = candY;\n        }\n    }\n\n    if (bestY > 100000) bestY = 100000;\n    if (bestY <= y1) bestY = y1 + 1;\n    return bestY;\n}\n\nstatic vector<Point> refine_rectangle_poly(\n    const vector<Point>& poly,\n    const vector<WPoint>& pts,\n    const Timer& timer,\n    double stop_ms\n) {\n    int x1, y1, x2, y2;\n    if (!extract_rectangle(poly, x1, y1, x2, y2)) return poly;\n\n    for (int it = 0; it < 3; it++) {\n        if (timer.over(stop_ms)) break;\n        int ox1 = x1, oy1 = y1, ox2 = x2, oy2 = y2;\n\n        x1 = optimize_left_edge(y1, y2, x2, pts);\n        if (x1 >= x2) x1 = x2 - 1;\n\n        x2 = optimize_right_edge(x1, y1, y2, pts);\n        if (x2 <= x1) x2 = x1 + 1;\n\n        y1 = optimize_bottom_edge(x1, x2, y2, pts);\n        if (y1 >= y2) y1 = y2 - 1;\n\n        y2 = optimize_top_edge(x1, x2, y1, pts);\n        if (y2 <= y1) y2 = y1 + 1;\n\n        x1 = max(0, min(x1, 99999));\n        y1 = max(0, min(y1, 99999));\n        x2 = max(1, min(x2, 100000));\n        y2 = max(1, min(y2, 100000));\n\n        if (x1 >= x2) x1 = max(0, x2 - 1);\n        if (y1 >= y2) y1 = max(0, y2 - 1);\n\n        if (x1 == ox1 && y1 == oy1 && x2 == ox2 && y2 == oy2) break;\n    }\n\n    vector<Point> res = build_rect_poly(x1, y1, x2, y2);\n    if (!legal_polygon(res)) return poly;\n    return res;\n}\n\nstatic void process_cut_grid(\n    const vector<WPoint>& pts,\n    const vector<int>& xs,\n    const vector<int>& ys,\n    const vector<int>& lambdas,\n    vector<Candidate>& cands,\n    const Timer& timer,\n    double time_limit_ms,\n    bool add_rect = true\n) {\n    int W = (int)xs.size() - 1;\n    int H = (int)ys.size() - 1;\n\n    vector<int> cell_w(W * H, 0);\n    for (auto &p : pts) {\n        int gx = find_cell(xs, p.x);\n        int gy = find_cell(ys, p.y);\n        cell_w[gy * W + gx] += p.w;\n    }\n\n    if (add_rect && !timer.over(time_limit_ms - 250)) {\n        Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n        if (!rect.poly.empty()) cands.push_back(move(rect));\n    }\n\n    for (int lambda : lambdas) {\n        if (timer.over(time_limit_ms)) break;\n\n        vector<char> sel = solve_selection_by_cut(cell_w, W, H, lambda);\n\n        bool any = false;\n        for (char c : sel) if (c) { any = true; break; }\n        if (!any) continue;\n\n        vector<char> base = sel;\n        fill_holes(base, W, H);\n\n        vector<vector<char>> variants;\n        variants.push_back(base);\n\n        if (!timer.over(time_limit_ms - 180)) {\n            vector<char> cleaned = base;\n            cleanup_selection(cleaned, cell_w, W, H);\n            fill_holes(cleaned, W, H);\n            variants.push_back(cleaned);\n        }\n\n        for (auto &cur_sel : variants) {\n            auto comps = get_components(cur_sel, cell_w, W, H);\n\n            int K = min(4, (int)comps.size());\n            for (int ci = 0; ci < K; ci++) {\n                vector<char> comp_sel(W * H, 0);\n                for (int v : comps[ci].cells) comp_sel[v] = 1;\n\n                PolyInfo info = build_polygon_from_component(comp_sel, W, H, xs, ys);\n                if (!info.ok) continue;\n                if (!legal_polygon(info.poly)) continue;\n                cands.push_back({info.poly, comps[ci].approx});\n            }\n\n            if (!timer.over(time_limit_ms - 120) && (int)comps.size() >= 2) {\n                Candidate cc = connect_top2_components_candidate(comps, cell_w, W, H, xs, ys);\n                if (!cc.poly.empty()) cands.push_back(move(cc));\n            }\n        }\n    }\n}\n\nstatic uint64_t canonical_hash_poly(const vector<Point>& poly) {\n    int n = (int)poly.size();\n    if (n == 0) return 0;\n\n    int s = 0;\n    for (int i = 1; i < n; i++) {\n        if (poly[i].x < poly[s].x || (poly[i].x == poly[s].x && poly[i].y < poly[s].y)) {\n            s = i;\n        }\n    }\n\n    auto get_fwd = [&](int k) -> const Point& {\n        return poly[(s + k) % n];\n    };\n    auto get_rev = [&](int k) -> const Point& {\n        return poly[(s - k + n) % n];\n    };\n\n    bool use_fwd = true;\n    for (int k = 1; k < n; k++) {\n        const Point& a = get_fwd(k);\n        const Point& b = get_rev(k);\n        if (a.x != b.x) {\n            use_fwd = a.x < b.x;\n            break;\n        }\n        if (a.y != b.y) {\n            use_fwd = a.y < b.y;\n            break;\n        }\n    }\n\n    uint64_t h = 1469598103934665603ULL;\n    for (int k = 0; k < n; k++) {\n        const Point& p = use_fwd ? get_fwd(k) : get_rev(k);\n        uint64_t v = (uint64_t(uint32_t(p.x)) << 32) ^ uint32_t(p.y);\n        h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)n * 1000003ULL;\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TIME_LIMIT_MS = 1850.0;\n\n    int N;\n    cin >> N;\n\n    vector<WPoint> pts;\n    pts.reserve(2 * N);\n    unordered_set<uint64_t> occ;\n    occ.reserve(4 * N);\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, +1});\n        occ.insert(pack_xy(x, y));\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        pts.push_back({x, y, -1});\n        occ.insert(pack_xy(x, y));\n    }\n\n    vector<Point> best_poly = fallback_polygon(occ);\n    int best_diff = exact_diff(best_poly, pts);\n\n    vector<Candidate> cands;\n    cands.reserve(1250);\n\n    // Main symmetric-offset cut search\n    const vector<int> cut_sizes = {1000, 750, 500};\n    for (int S : cut_sizes) {\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        vector<int> offsets = {0};\n        if (S / 2 > 0) offsets.push_back(S / 2);\n\n        vector<int> lambdas;\n        if (S >= 900) lambdas = {0, 1, 2, 4, 8};\n        else if (S >= 700) lambdas = {0, 1, 2, 3, 5};\n        else lambdas = {0, 1, 2, 3, 4};\n\n        for (int off : offsets) {\n            if (timer.over(TIME_LIMIT_MS)) break;\n            vector<int> xs = build_lines(S, off);\n            vector<int> ys = build_lines(S, off);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS, true);\n        }\n    }\n\n    // Limited symmetric-offset cuts: S=625\n    if (!timer.over(TIME_LIMIT_MS - 340)) {\n        int S = 625;\n        vector<int> offsets = {0, S / 2};\n        vector<int> lambdas = {1, 2};\n        for (int off : offsets) {\n            if (timer.over(TIME_LIMIT_MS - 240)) break;\n            vector<int> xs = build_lines(S, off);\n            vector<int> ys = build_lines(S, off);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS - 90, false);\n        }\n    }\n\n    // Limited asymmetric-offset cuts: S=625 (improved: lambda {1,2})\n    if (!timer.over(TIME_LIMIT_MS - 320)) {\n        int S = 625;\n        vector<pair<int,int>> off_pairs = {{0, S / 2}, {S / 2, 0}};\n        vector<int> lambdas = {1, 2};\n        for (auto [offx, offy] : off_pairs) {\n            if (timer.over(TIME_LIMIT_MS - 220)) break;\n            vector<int> xs = build_lines(S, offx);\n            vector<int> ys = build_lines(S, offy);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS - 70, false);\n        }\n    }\n\n    // Limited asymmetric-offset cuts: S=1000\n    if (!timer.over(TIME_LIMIT_MS - 300)) {\n        int S = 1000;\n        vector<pair<int,int>> off_pairs = {{0, S / 2}, {S / 2, 0}};\n        vector<int> lambdas = {1};\n\n        for (auto [offx, offy] : off_pairs) {\n            if (timer.over(TIME_LIMIT_MS - 250)) break;\n            vector<int> xs = build_lines(S, offx);\n            vector<int> ys = build_lines(S, offy);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS - 90, false);\n        }\n    }\n\n    // Limited asymmetric-offset cuts: S=750\n    if (!timer.over(TIME_LIMIT_MS - 270)) {\n        int S = 750;\n        vector<pair<int,int>> off_pairs = {{0, S / 2}, {S / 2, 0}};\n        vector<int> lambdas = {1, 2};\n\n        for (auto [offx, offy] : off_pairs) {\n            if (timer.over(TIME_LIMIT_MS - 190)) break;\n            vector<int> xs = build_lines(S, offx);\n            vector<int> ys = build_lines(S, offy);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS - 60, false);\n        }\n    }\n\n    // Limited asymmetric-offset cuts: S=500\n    if (!timer.over(TIME_LIMIT_MS - 230)) {\n        int S = 500;\n        vector<pair<int,int>> off_pairs = {{0, S / 2}, {S / 2, 0}};\n        vector<int> lambdas = {1, 3};\n\n        for (auto [offx, offy] : off_pairs) {\n            if (timer.over(TIME_LIMIT_MS - 120)) break;\n            vector<int> xs = build_lines(S, offx);\n            vector<int> ys = build_lines(S, offy);\n            process_cut_grid(pts, xs, ys, lambdas, cands, timer, TIME_LIMIT_MS - 30, false);\n        }\n    }\n\n    // Rectangle-only extra search with independent offsets\n    if (!timer.over(TIME_LIMIT_MS - 230)) {\n        const vector<int> rect_sizes = {1000, 750, 625, 500, 400};\n        for (int S : rect_sizes) {\n            if (timer.over(TIME_LIMIT_MS - 80)) break;\n\n            vector<int> offs = {0};\n            if (S / 2 > 0) offs.push_back(S / 2);\n\n            for (int offx : offs) {\n                for (int offy : offs) {\n                    if (timer.over(TIME_LIMIT_MS - 80)) break;\n\n                    vector<int> xs = build_lines(S, offx);\n                    vector<int> ys = build_lines(S, offy);\n                    int W = (int)xs.size() - 1;\n                    int H = (int)ys.size() - 1;\n\n                    vector<int> cell_w(W * H, 0);\n                    for (auto &p : pts) {\n                        int gx = find_cell(xs, p.x);\n                        int gy = find_cell(ys, p.y);\n                        cell_w[gy * W + gx] += p.w;\n                    }\n\n                    Candidate rect = max_sum_rectangle_candidate(cell_w, W, H, xs, ys);\n                    if (!rect.poly.empty()) cands.push_back(move(rect));\n                }\n            }\n        }\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.poly.size() != b.poly.size()) return a.poly.size() < b.poly.size();\n        return polygon_perimeter(a.poly) < polygon_perimeter(b.poly);\n    });\n\n    vector<Candidate> filtered;\n    filtered.reserve(cands.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(cands.size() * 2 + 1);\n\n    for (auto &c : cands) {\n        uint64_t h = canonical_hash_poly(c.poly);\n        if (seen.insert(h).second) filtered.push_back(move(c));\n    }\n\n    int REFINE_LIMIT = min(20, (int)filtered.size());\n    for (int i = 0; i < REFINE_LIMIT; i++) {\n        if (timer.over(1910.0)) break;\n        int x1, y1, x2, y2;\n        if (!extract_rectangle(filtered[i].poly, x1, y1, x2, y2)) continue;\n        vector<Point> refined = refine_rectangle_poly(filtered[i].poly, pts, timer, 1930.0);\n        int diff = exact_diff(refined, pts);\n        if (diff > best_diff) {\n            best_diff = diff;\n            best_poly = refined;\n        }\n    }\n\n    int LIMIT = min(80, (int)filtered.size());\n    for (int i = 0; i < LIMIT; i++) {\n        if (timer.over(1970.0)) break;\n        int diff = exact_diff(filtered[i].poly, pts);\n        if (diff > best_diff) {\n            best_diff = diff;\n            best_poly = filtered[i].poly;\n        }\n    }\n\n    cout << best_poly.size() << '\\n';\n    for (auto &p : best_poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nusing ld = long double;\n\nstatic constexpr ll INF64 = (1LL << 62);\n\nstruct Op {\n    int p, r;\n    char d;\n    int b;\n};\n\nstruct Placed {\n    ll x = 0, y = 0, w = 0, h = 0;\n    bool used = false;\n};\n\nstruct Candidate {\n    ll estW = 0, estH = 0, est = 0;\n    bool isRow = true;\n    int anchorStrategy = 0;\n    vector<Op> ops;\n    string sig;\n\n    vector<int> rot;\n    vector<pair<int,int>> segs;\n};\n\nint N, T, sigma_;\nvector<ll> obsW, obsH;\n\nbool overlap1D(ll l1, ll r1, ll l2, ll r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nbool betterWH(ll W1, ll H1, ll W2, ll H2) {\n    if (W1 + H1 != W2 + H2) return W1 + H1 < W2 + H2;\n    if (max(W1, H1) != max(W2, H2)) return max(W1, H1) < max(W2, H2);\n    if (W1 != W2) return W1 < W2;\n    return H1 < H2;\n}\n\nbool betterCand(const Candidate& a, const Candidate& b) {\n    if (a.est != b.est) return a.est < b.est;\n    if (max(a.estW, a.estH) != max(b.estW, b.estH)) return max(a.estW, a.estH) < max(b.estW, b.estH);\n    if (a.estW != b.estW) return a.estW < b.estW;\n    if (a.estH != b.estH) return a.estH < b.estH;\n    return a.sig < b.sig;\n}\n\nvoid place_one(int p, int r, char d, int b, const vector<ll>& baseW, const vector<ll>& baseH,\n               vector<Placed>& placed, ll& W, ll& H) {\n    ll w = (r == 0 ? baseW[p] : baseH[p]);\n    ll h = (r == 0 ? baseH[p] : baseW[p]);\n\n    ll x = 0, y = 0;\n    if (d == 'U') {\n        x = (b == -1 ? 0 : placed[b].x + placed[b].w);\n        y = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(x, x + w, placed[i].x, placed[i].x + placed[i].w)) {\n                y = max(y, placed[i].y + placed[i].h);\n            }\n        }\n    } else {\n        y = (b == -1 ? 0 : placed[b].y + placed[b].h);\n        x = 0;\n        for (int i = 0; i < N; i++) {\n            if (!placed[i].used) continue;\n            if (overlap1D(y, y + h, placed[i].y, placed[i].y + placed[i].h)) {\n                x = max(x, placed[i].x + placed[i].w);\n            }\n        }\n    }\n\n    placed[p] = {x, y, w, h, true};\n    W = max(W, x + w);\n    H = max(H, y + h);\n}\n\npair<ll,ll> simulate_ops(const vector<Op>& ops, const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<Placed> placed(N);\n    ll W = 0, H = 0;\n    for (const auto& op : ops) {\n        place_one(op.p, op.r, op.d, op.b, baseW, baseH, placed, W, H);\n    }\n    return {W, H};\n}\n\nstring ops_signature(const vector<Op>& ops) {\n    string s;\n    s.reserve(ops.size() * 5);\n    for (const auto& op : ops) {\n        s.push_back(char('0' + op.r));\n        s.push_back(op.d);\n        int x = op.b + 1;\n        s.push_back(char('A' + (x / 26)));\n        s.push_back(char('A' + (x % 26)));\n    }\n    return s;\n}\n\nvoid reevaluate(Candidate& c, const vector<ll>& evalW, const vector<ll>& evalH) {\n    auto [W, H] = simulate_ops(c.ops, evalW, evalH);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n}\n\nvector<pair<int,int>> partition_strip(const vector<ll>& primary, const vector<ll>& secondary, ll cap) {\n    vector<ll> dp(N + 1, INF64);\n    vector<int> cnt(N + 1, INT_MAX), prv(N + 1, -1);\n    dp[0] = 0;\n    cnt[0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        if (dp[i] >= INF64 / 2) continue;\n        ll sumP = 0, mxS = 0;\n        for (int j = i; j < N; j++) {\n            sumP += primary[j];\n            if (sumP > cap) break;\n            mxS = max(mxS, secondary[j]);\n\n            ll ndp = dp[i] + mxS;\n            int ncnt = cnt[i] + 1;\n            if (ndp < dp[j + 1] || (ndp == dp[j + 1] && ncnt < cnt[j + 1])) {\n                dp[j + 1] = ndp;\n                cnt[j + 1] = ncnt;\n                prv[j + 1] = i;\n            }\n        }\n    }\n\n    if (prv[N] == -1) return {};\n\n    vector<pair<int,int>> segs;\n    int cur = N;\n    while (cur > 0) {\n        int p = prv[cur];\n        segs.push_back({p, cur});\n        cur = p;\n    }\n    reverse(segs.begin(), segs.end());\n    return segs;\n}\n\nvector<ll> generate_caps(const vector<ll>& primary, const vector<ll>& secondary) {\n    ll total = 0, mx = 0;\n    ld area = 0;\n    for (int i = 0; i < N; i++) {\n        total += primary[i];\n        mx = max(mx, primary[i]);\n        area += (ld)primary[i] * (ld)secondary[i];\n    }\n\n    vector<ll> vals;\n    vals.push_back(mx);\n\n    static const ld mults1[] = {0.68L, 0.80L, 0.92L, 1.00L, 1.10L, 1.25L, 1.45L};\n    int K = min(N, 18);\n    for (int k = 1; k <= K; k++) {\n        ld base = (ld)total / (ld)k;\n        for (ld m : mults1) vals.push_back(max(mx, (ll)llround(base * m)));\n    }\n\n    ld sq = sqrt(area);\n    static const ld mults2[] = {0.55L, 0.70L, 0.85L, 1.00L, 1.20L, 1.45L, 1.80L};\n    for (ld m : mults2) vals.push_back(max(mx, (ll)llround(sq * m)));\n\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end()), vals.end());\n\n    if ((int)vals.size() > 44) {\n        vector<ll> sampled;\n        sampled.reserve(44);\n        for (int i = 0; i < 44; i++) {\n            int idx = (int)((ld)i * (ld)(vals.size() - 1) / 43.0L);\n            if (sampled.empty() || sampled.back() != vals[idx]) sampled.push_back(vals[idx]);\n        }\n        vals.swap(sampled);\n    }\n    return vals;\n}\n\nvector<vector<int>> generate_rotation_modes(const vector<ll>& baseW, const vector<ll>& baseH) {\n    vector<vector<int>> modes;\n    unordered_set<string> seen;\n\n    auto add_mode = [&](const vector<int>& rot) {\n        string s;\n        s.reserve(N);\n        for (int x : rot) s.push_back(char('0' + x));\n        if (seen.insert(s).second) modes.push_back(rot);\n    };\n\n    vector<int> all0(N, 0), all1(N, 1), minW(N), minH(N);\n    vector<ll> mxs(N);\n    for (int i = 0; i < N; i++) {\n        minW[i] = (baseW[i] <= baseH[i] ? 0 : 1);\n        minH[i] = (baseH[i] <= baseW[i] ? 0 : 1);\n        mxs[i] = max(baseW[i], baseH[i]);\n    }\n\n    add_mode(all0);\n    add_mode(all1);\n    add_mode(minW);\n    add_mode(minH);\n\n    auto sortedMx = mxs;\n    sort(sortedMx.begin(), sortedMx.end());\n    ll th1 = sortedMx[N / 2];\n    ll th2 = sortedMx[(3 * N) / 4];\n\n    vector<int> hy1(N), hy2(N), hy3(N);\n    for (int i = 0; i < N; i++) {\n        hy1[i] = (mxs[i] >= th1 ? minW[i] : minH[i]);\n        hy2[i] = (mxs[i] >= th2 ? minW[i] : minH[i]);\n        hy3[i] = (mxs[i] >= th1 ? minH[i] : minW[i]);\n    }\n    add_mode(hy1);\n    add_mode(hy2);\n    add_mode(hy3);\n\n    ll near_thr = 2LL * sigma_;\n    vector<vector<int>> bases = {minW, minH, hy1, hy2};\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int seed = 0; seed < 2; seed++) {\n            vector<int> rot = bases[bi];\n            mt19937 rng(1234567 + 1009 * bi + seed);\n            for (int i = 0; i < N; i++) {\n                if (llabs(baseW[i] - baseH[i]) <= near_thr) {\n                    if (rng() & 1) rot[i] ^= 1;\n                }\n            }\n            add_mode(rot);\n        }\n    }\n\n    return modes;\n}\n\nCandidate build_row_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& buildW, const vector<ll>& buildH) {\n    Candidate c;\n    c.isRow = true;\n    c.anchorStrategy = strategy;\n    c.rot = rot;\n    c.segs = segs;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto bottom = [&](int idx) -> ll {\n        return placed[idx].y + placed[idx].h;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'U', -1});\n            place_one(l, rot[l], 'U', -1, buildW, buildH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'L', b});\n            place_one(l, rot[l], 'L', b, buildW, buildH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'U', i - 1});\n            place_one(i, rot[i], 'U', i - 1, buildW, buildH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (bottom(i) > bottom(prevMax)) prevMax = i;\n            if (bottom(i) < bottom(prevMin)) prevMin = i;\n        }\n        if (globalMax == -1 || bottom(prevMax) > bottom(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || bottom(prevMin) < bottom(globalMin)) globalMin = prevMin;\n    }\n\n    c.ops = move(ops);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nCandidate build_col_candidate(const vector<pair<int,int>>& segs, const vector<int>& rot, int strategy,\n                              const vector<ll>& buildW, const vector<ll>& buildH) {\n    Candidate c;\n    c.isRow = false;\n    c.anchorStrategy = strategy;\n    c.rot = rot;\n    c.segs = segs;\n\n    vector<Placed> placed(N);\n    vector<Op> ops;\n    ops.reserve(N);\n    ll W = 0, H = 0;\n\n    int prevFirst = -1, prevLast = -1, prevMax = -1, prevMin = -1;\n    int globalMax = -1, globalMin = -1;\n\n    auto right = [&](int idx) -> ll {\n        return placed[idx].x + placed[idx].w;\n    };\n    auto choose_anchor = [&]() -> int {\n        switch (strategy) {\n            case 0: return prevMax;\n            case 1: return prevLast;\n            case 2: return prevFirst;\n            case 3: return globalMax;\n            case 4: return globalMin;\n        }\n        return prevMax;\n    };\n\n    for (int s = 0; s < (int)segs.size(); s++) {\n        auto [l, r] = segs[s];\n\n        if (s == 0) {\n            ops.push_back({l, rot[l], 'L', -1});\n            place_one(l, rot[l], 'L', -1, buildW, buildH, placed, W, H);\n        } else {\n            int b = choose_anchor();\n            if (b < 0) b = prevMax;\n            if (b < 0) b = prevLast;\n            if (b < 0) b = prevFirst;\n            if (b < 0) b = -1;\n            ops.push_back({l, rot[l], 'U', b});\n            place_one(l, rot[l], 'U', b, buildW, buildH, placed, W, H);\n        }\n\n        for (int i = l + 1; i < r; i++) {\n            ops.push_back({i, rot[i], 'L', i - 1});\n            place_one(i, rot[i], 'L', i - 1, buildW, buildH, placed, W, H);\n        }\n\n        prevFirst = l;\n        prevLast = r - 1;\n        prevMax = l;\n        prevMin = l;\n        for (int i = l; i < r; i++) {\n            if (right(i) > right(prevMax)) prevMax = i;\n            if (right(i) < right(prevMin)) prevMin = i;\n        }\n        if (globalMax == -1 || right(prevMax) > right(globalMax)) globalMax = prevMax;\n        if (globalMin == -1 || right(prevMin) < right(globalMin)) globalMin = prevMin;\n    }\n\n    c.ops = move(ops);\n    c.estW = W;\n    c.estH = H;\n    c.est = W + H;\n    c.sig = ops_signature(c.ops);\n    return c;\n}\n\nCandidate rebuild_candidate(bool isRow, const vector<pair<int,int>>& segs, const vector<int>& rot,\n                            int strategy, const vector<ll>& buildW, const vector<ll>& buildH,\n                            const vector<ll>& evalW, const vector<ll>& evalH) {\n    Candidate c = isRow\n        ? build_row_candidate(segs, rot, strategy, buildW, buildH)\n        : build_col_candidate(segs, rot, strategy, buildW, buildH);\n    reevaluate(c, evalW, evalH);\n    return c;\n}\n\nCandidate refine_anchor_strategy(const Candidate& base,\n                                 const vector<ll>& buildW, const vector<ll>& buildH,\n                                 const vector<ll>& evalW, const vector<ll>& evalH) {\n    Candidate best = base;\n    for (int s = 0; s < 5; s++) {\n        Candidate c = rebuild_candidate(base.isRow, base.segs, base.rot, s, buildW, buildH, evalW, evalH);\n        if (betterCand(c, best)) best = move(c);\n    }\n    return best;\n}\n\nCandidate improve_partition_structure(Candidate best,\n                                      const vector<ll>& buildW, const vector<ll>& buildH,\n                                      const vector<ll>& evalW, const vector<ll>& evalH) {\n    for (int iter = 0; iter < 3; iter++) {\n        Candidate bestLocal = best;\n\n        auto try_segs = [&](const vector<pair<int,int>>& segs2) {\n            Candidate c = rebuild_candidate(best.isRow, segs2, best.rot, best.anchorStrategy,\n                                            buildW, buildH, evalW, evalH);\n            if (betterCand(c, bestLocal)) bestLocal = move(c);\n        };\n\n        for (int s = 0; s + 1 < (int)best.segs.size(); s++) {\n            int l1 = best.segs[s].first, r1 = best.segs[s].second;\n            int l2 = best.segs[s + 1].first, r2 = best.segs[s + 1].second;\n            int len1 = r1 - l1, len2 = r2 - l2;\n\n            for (int d : {-2, -1, 1, 2}) {\n                if (d > 0) {\n                    if (len2 <= d) continue;\n                    auto segs2 = best.segs;\n                    segs2[s].second += d;\n                    segs2[s + 1].first += d;\n                    try_segs(segs2);\n                } else {\n                    int t = -d;\n                    if (len1 <= t) continue;\n                    auto segs2 = best.segs;\n                    segs2[s].second -= t;\n                    segs2[s + 1].first -= t;\n                    try_segs(segs2);\n                }\n            }\n        }\n\n        for (int s = 0; s + 1 < (int)best.segs.size(); s++) {\n            auto segs2 = best.segs;\n            segs2[s] = {segs2[s].first, segs2[s + 1].second};\n            segs2.erase(segs2.begin() + (s + 1));\n            try_segs(segs2);\n        }\n\n        for (int s = 0; s < (int)best.segs.size(); s++) {\n            int l = best.segs[s].first, r = best.segs[s].second;\n            if (r - l <= 1) continue;\n            for (int k = l + 1; k < r; k++) {\n                auto segs2 = best.segs;\n                segs2[s] = {l, k};\n                segs2.insert(segs2.begin() + s + 1, {k, r});\n                try_segs(segs2);\n            }\n        }\n\n        if (betterCand(bestLocal, best)) best = move(bestLocal);\n        else break;\n    }\n    return best;\n}\n\nCandidate improve_rotations(Candidate best, const vector<ll>& evalW, const vector<ll>& evalH) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        ll pa = evalW[a] + evalH[a];\n        ll pb = evalW[b] + evalH[b];\n        ll da = llabs(evalW[a] - evalH[a]);\n        ll db = llabs(evalW[b] - evalH[b]);\n        if (pa != pb) return pa > pb;\n        return da < db;\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (int p : order) {\n            vector<Op> ops2 = best.ops;\n            ops2[p].r ^= 1;\n            auto [W2, H2] = simulate_ops(ops2, evalW, evalH);\n            if (betterWH(W2, H2, best.estW, best.estH)) {\n                best.ops.swap(ops2);\n                best.rot[p] ^= 1;\n                best.estW = W2;\n                best.estH = H2;\n                best.est = W2 + H2;\n                best.sig = ops_signature(best.ops);\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n    return best;\n}\n\nvector<Candidate> generate_candidates_for_base(const vector<ll>& buildW, const vector<ll>& buildH,\n                                               const vector<ll>& evalW, const vector<ll>& evalH) {\n    vector<Candidate> cands;\n    unordered_set<string> usedSig;\n\n    auto add_candidate = [&](Candidate&& c) {\n        if ((int)c.ops.size() != N) return;\n        reevaluate(c, evalW, evalH);\n        if (usedSig.insert(c.sig).second) cands.push_back(move(c));\n    };\n\n    auto rotModes = generate_rotation_modes(buildW, buildH);\n\n    for (const auto& rot : rotModes) {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = (rot[i] == 0 ? buildW[i] : buildH[i]);\n            h[i] = (rot[i] == 0 ? buildH[i] : buildW[i]);\n        }\n\n        auto capsR = generate_caps(w, h);\n        for (ll cap : capsR) {\n            auto segs = partition_strip(w, h, cap);\n            if (segs.empty()) continue;\n            for (int strat = 0; strat < 5; strat++) {\n                add_candidate(build_row_candidate(segs, rot, strat, buildW, buildH));\n            }\n        }\n\n        auto capsC = generate_caps(h, w);\n        for (ll cap : capsC) {\n            auto segs = partition_strip(h, w, cap);\n            if (segs.empty()) continue;\n            for (int strat = 0; strat < 5; strat++) {\n                add_candidate(build_col_candidate(segs, rot, strat, buildW, buildH));\n            }\n        }\n    }\n\n    if (cands.empty()) {\n        vector<int> rot(N, 0);\n        vector<pair<int,int>> segs = {{0, N}};\n        add_candidate(build_row_candidate(segs, rot, 0, buildW, buildH));\n        add_candidate(build_col_candidate(segs, rot, 0, buildW, buildH));\n    }\n\n    sort(cands.begin(), cands.end(), betterCand);\n\n    int topK = min(10, (int)cands.size());\n    vector<Candidate> extra;\n    extra.reserve(topK);\n\n    for (int i = 0; i < topK; i++) {\n        Candidate c = cands[i];\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        c = improve_partition_structure(c, buildW, buildH, evalW, evalH);\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        c = improve_rotations(c, evalW, evalH);\n        c = refine_anchor_strategy(c, buildW, buildH, evalW, evalH);\n        if (usedSig.insert(c.sig).second) extra.push_back(move(c));\n    }\n\n    for (auto& c : extra) cands.push_back(move(c));\n    sort(cands.begin(), cands.end(), betterCand);\n    return cands;\n}\n\nvector<Candidate> generate_candidates_from_views(\n    const vector<pair<vector<ll>, vector<ll>>>& views,\n    const vector<ll>& evalW, const vector<ll>& evalH\n) {\n    vector<Candidate> all;\n    unordered_set<string> used;\n\n    for (const auto& vw : views) {\n        auto pool = generate_candidates_for_base(vw.first, vw.second, evalW, evalH);\n        for (auto& c : pool) {\n            if (used.insert(c.sig).second) all.push_back(move(c));\n        }\n    }\n\n    sort(all.begin(), all.end(), betterCand);\n    return all;\n}\n\nvoid append_unique_candidates(vector<Candidate>& candidates, vector<char>& usedFlag, vector<Candidate> add) {\n    unordered_set<string> seen;\n    seen.reserve(candidates.size() * 2 + add.size() * 2 + 1);\n    for (auto& c : candidates) seen.insert(c.sig);\n\n    for (auto& c : add) {\n        if (seen.insert(c.sig).second) {\n            candidates.push_back(move(c));\n            usedFlag.push_back(0);\n        }\n    }\n    // Do NOT sort here: usedFlag is parallel to candidates.\n    // Re-sorting without reordering usedFlag would corrupt bookkeeping.\n}\n\nvoid output_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T >> sigma_;\n    obsW.resize(N);\n    obsH.resize(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    int probeTurns = 0;\n    if (sigma_ >= 3000) probeTurns++;\n    if (sigma_ >= 5500) probeTurns++;\n    if (sigma_ >= 8000) probeTurns++;\n    if (sigma_ >= 9500) probeTurns++;\n    if (T >= 2 * N) probeTurns++;\n    probeTurns = min(probeTurns, max(0, T - 8));\n    probeTurns = min(probeTurns, 5);\n\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        ll ambA = max<ll>(0, 2LL * sigma_ - llabs(obsW[a] - obsH[a]));\n        ll ambB = max<ll>(0, 2LL * sigma_ - llabs(obsW[b] - obsH[b]));\n        ll sa = 2 * (obsW[a] + obsH[a]) + ambA;\n        ll sb = 2 * (obsW[b] + obsH[b]) + ambB;\n        if (sa != sb) return sa > sb;\n        return a < b;\n    });\n\n    vector<ld> sumW(N), sumH(N);\n    vector<int> cnt(N, 1);\n    for (int i = 0; i < N; i++) {\n        sumW[i] = obsW[i];\n        sumH[i] = obsH[i];\n    }\n\n    for (int t = 0; t < probeTurns; t++) {\n        int p = ord[t % N];\n        vector<Op> ops = {{p, 0, 'U', -1}};\n        output_ops(ops);\n\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n\n        sumW[p] += Wm;\n        sumH[p] += Hm;\n        cnt[p]++;\n    }\n\n    vector<ll> estW(N), estH(N);\n    for (int i = 0; i < N; i++) {\n        estW[i] = max<ll>(1, llround(sumW[i] / cnt[i]));\n        estH[i] = max<ll>(1, llround(sumH[i] / cnt[i]));\n    }\n\n    vector<pair<vector<ll>, vector<ll>>> initViews;\n    initViews.push_back({obsW, obsH});\n    bool diffRE = false;\n    for (int i = 0; i < N; i++) {\n        if (obsW[i] != estW[i] || obsH[i] != estH[i]) {\n            diffRE = true;\n            break;\n        }\n    }\n    if (diffRE) {\n        vector<ll> midW(N), midH(N);\n        for (int i = 0; i < N; i++) {\n            midW[i] = max<ll>(1, (obsW[i] + estW[i]) / 2);\n            midH[i] = max<ll>(1, (obsH[i] + estH[i]) / 2);\n        }\n        initViews.push_back({midW, midH});\n    }\n    initViews.push_back({estW, estH});\n\n    vector<Candidate> candidates = generate_candidates_from_views(initViews, estW, estH);\n    if (candidates.empty()) return 0;\n    vector<char> used(candidates.size(), 0);\n\n    auto best_by = [&](auto fn) -> int {\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = fn(candidates[i]);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    vector<int> initialPlan;\n    {\n        int x;\n        x = best_by([&](const Candidate& c) { return (ld)c.est; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return c.isRow ? (ld)c.est : 1e99L; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return (!c.isRow) ? (ld)c.est : 1e99L; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return 1.18L * (ld)c.estW + 0.82L * (ld)c.estH; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return 0.82L * (ld)c.estW + 1.18L * (ld)c.estH; });\n        if (x != -1) initialPlan.push_back(x);\n\n        x = best_by([&](const Candidate& c) { return (ld)max(c.estW, c.estH); });\n        if (x != -1) initialPlan.push_back(x);\n    }\n\n    {\n        vector<int> uniq;\n        vector<char> seen(candidates.size(), 0);\n        for (int x : initialPlan) {\n            if (x >= 0 && !seen[x]) {\n                seen[x] = 1;\n                uniq.push_back(x);\n            }\n        }\n        initialPlan.swap(uniq);\n    }\n\n    ld sumEstWQ = 0, sumEstHQ = 0;\n    ld sumMeasWQ = 0, sumMeasHQ = 0;\n    const ld prior = 1e6L;\n\n    auto pick_best_adjusted = [&]() -> int {\n        ld scaleW = (sumMeasWQ + prior) / (sumEstWQ + prior);\n        ld scaleH = (sumMeasHQ + prior) / (sumEstHQ + prior);\n\n        int best = -1;\n        ld bestScore = 1e100L;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (used[i]) continue;\n            ld sc = scaleW * (ld)candidates[i].estW + scaleH * (ld)candidates[i].estH;\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return best;\n    };\n\n    bool regenerated = false;\n    int actualTurnsDone = 0;\n    int totalActualTurns = T - probeTurns;\n    int regenTrigger = max(3, min(6, totalActualTurns / 3));\n\n    for (int turn = probeTurns; turn < T; turn++) {\n        int localTurn = turn - probeTurns;\n        int idx = -1;\n\n        if (localTurn < (int)initialPlan.size() && !used[initialPlan[localTurn]]) {\n            idx = initialPlan[localTurn];\n        } else {\n            idx = pick_best_adjusted();\n        }\n\n        if (idx == -1) idx = 0;\n        used[idx] = 1;\n\n        output_ops(candidates[idx].ops);\n\n        ll measW, measH;\n        if (!(cin >> measW >> measH)) return 0;\n\n        sumEstWQ += (ld)candidates[idx].estW;\n        sumEstHQ += (ld)candidates[idx].estH;\n        sumMeasWQ += (ld)measW;\n        sumMeasHQ += (ld)measH;\n        actualTurnsDone++;\n\n        int turnsLeft = T - (turn + 1);\n        if (!regenerated && actualTurnsDone >= regenTrigger && turnsLeft >= 4) {\n            ld scaleW = (sumMeasWQ + prior) / (sumEstWQ + prior);\n            ld scaleH = (sumMeasHQ + prior) / (sumEstHQ + prior);\n\n            ld dev = max(fabsl(log(scaleW)), fabsl(log(scaleH)));\n            if (dev >= 0.035L) {\n                scaleW = min<ld>(1.10L, max<ld>(0.90L, scaleW));\n                scaleH = min<ld>(1.10L, max<ld>(0.90L, scaleH));\n\n                vector<ll> scaledW(N), scaledH(N), blendW(N), blendH(N);\n                for (int i = 0; i < N; i++) {\n                    scaledW[i] = max<ll>(1, llround((ld)estW[i] * scaleW));\n                    scaledH[i] = max<ll>(1, llround((ld)estH[i] * scaleH));\n                    blendW[i] = max<ll>(1, llround(((ld)estW[i] + (ld)scaledW[i]) * 0.5L));\n                    blendH[i] = max<ll>(1, llround(((ld)estH[i] + (ld)scaledH[i]) * 0.5L));\n                }\n\n                vector<pair<vector<ll>, vector<ll>>> newViews;\n                newViews.push_back({blendW, blendH});\n                newViews.push_back({scaledW, scaledH});\n\n                auto extra = generate_candidates_from_views(newViews, scaledW, scaledH);\n                append_unique_candidates(candidates, used, move(extra));\n            }\n            regenerated = true;\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> X, Y, degv;\n    vector<double> rad;\n\n    mt19937 rng{(uint32_t)chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    // =========================================================\n    // permutation -> forest\n    // =========================================================\n    long long eval_perm(const vector<int>& perm,\n                        vector<int>* out_parent = nullptr,\n                        vector<int>* out_depth = nullptr) {\n        vector<int> pos(N), depth(N, 0);\n        for (int i = 0; i < N; i++) pos[perm[i]] = i;\n\n        vector<int> parent;\n        if (out_parent) parent.assign(N, -1);\n\n        long long score = 0;\n        for (int i = 0; i < N; i++) {\n            int v = perm[i];\n            int best_d = -1;\n            int best_p = -1;\n\n            for (int u : g[v]) {\n                if (pos[u] >= i) continue;\n                int du = depth[u];\n                if (du >= H) continue;\n                if (du > best_d) {\n                    best_d = du;\n                    best_p = u;\n                } else if (du == best_d && best_p != -1) {\n                    if (A[u] < A[best_p] ||\n                        (A[u] == A[best_p] && degv[u] > degv[best_p]) ||\n                        (A[u] == A[best_p] && degv[u] == degv[best_p] && rad[u] < rad[best_p])) {\n                        best_p = u;\n                    }\n                } else if (du == best_d && best_p == -1) {\n                    best_p = u;\n                }\n            }\n\n            if (best_p == -1) {\n                depth[v] = 0;\n                if (out_parent) parent[v] = -1;\n            } else {\n                depth[v] = best_d + 1;\n                if (out_parent) parent[v] = best_p;\n            }\n            score += 1LL * (depth[v] + 1) * A[v];\n        }\n\n        if (out_parent) *out_parent = move(parent);\n        if (out_depth) *out_depth = move(depth);\n        return score;\n    }\n\n    long long score_of_perm(const vector<int>& perm) {\n        return eval_perm(perm, nullptr, nullptr);\n    }\n\n    vector<int> make_perm_by_key(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_initial_perm(int mode) {\n        vector<double> key(N, 0.0);\n\n        if (mode == 0) {\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] + 1e-6 * v;\n            }\n        } else if (mode == 1) {\n            for (int v = 0; v < N; v++) {\n                key[v] = 10.0 * A[v] - 11.0 * degv[v] + 0.1 * rad[v] + 1e-6 * v;\n            }\n        } else if (mode == 2) {\n            for (int v = 0; v < N; v++) {\n                key[v] = 8.0 * A[v] - 8.0 * degv[v] + 0.8 * rad[v] + 1e-6 * v;\n            }\n        } else if (mode == 3) {\n            for (int v = 0; v < N; v++) {\n                key[v] = 7.0 * A[v] - 10.0 * degv[v] + 1.5 * rad[v] + 1e-6 * v;\n            }\n        } else {\n            double theta = uniform_real_distribution<double>(0.0, 2.0 * acos(-1.0))(rng);\n            double c = cos(theta), s = sin(theta);\n            double wa = uniform_real_distribution<double>(5.0, 12.0)(rng);\n            double wd = uniform_real_distribution<double>(6.0, 14.0)(rng);\n            double wr = uniform_real_distribution<double>(0.0, 1.8)(rng);\n            double wp = uniform_real_distribution<double>(-0.7, 0.7)(rng);\n\n            for (int v = 0; v < N; v++) {\n                double proj = X[v] * c + Y[v] * s;\n                key[v] = proj + wa * A[v] - wd * degv[v] + wr * rad[v] + wp * (X[v] - Y[v]) + 1e-7 * v;\n            }\n        }\n        return make_perm_by_key(key);\n    }\n\n    // =========================================================\n    // permutation local search\n    // =========================================================\n    void random_insert_move(vector<int>& p, int i, int j) {\n        if (i == j) return;\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    }\n\n    int pick_high_beauty_idx(const vector<int>& perm) {\n        int best = uniform_int_distribution<int>(0, N - 1)(rng);\n        for (int t = 0; t < 20; t++) {\n            int i = uniform_int_distribution<int>(0, N - 1)(rng);\n            if (A[perm[i]] > A[perm[best]]) best = i;\n        }\n        return best;\n    }\n\n    int pick_support_idx(const vector<int>& perm) {\n        auto val = [&](int v) -> int {\n            return 4 * degv[v] - 3 * A[v] - (int)(rad[v] / 20.0);\n        };\n        int best = uniform_int_distribution<int>(0, N - 1)(rng);\n        for (int t = 0; t < 20; t++) {\n            int i = uniform_int_distribution<int>(0, N - 1)(rng);\n            if (val(perm[i]) > val(perm[best])) best = i;\n        }\n        return best;\n    }\n\n    void perturb_perm(vector<int>& p) {\n        int ops = uniform_int_distribution<int>(2, 5)(rng);\n        for (int z = 0; z < ops; z++) {\n            int typ = uniform_int_distribution<int>(0, 99)(rng);\n            if (typ < 35) {\n                int i = pick_high_beauty_idx(p);\n                if (i + 1 < N) {\n                    int span = min(N - 1 - i, uniform_int_distribution<int>(20, 180)(rng));\n                    int j = i + uniform_int_distribution<int>(1, max(1, span))(rng);\n                    random_insert_move(p, i, j);\n                }\n            } else if (typ < 70) {\n                int i = pick_support_idx(p);\n                if (i > 0) {\n                    int span = min(i, uniform_int_distribution<int>(20, 180)(rng));\n                    int j = i - uniform_int_distribution<int>(1, max(1, span))(rng);\n                    random_insert_move(p, i, j);\n                }\n            } else if (typ < 88) {\n                int i = uniform_int_distribution<int>(0, N - 2)(rng);\n                int d = uniform_int_distribution<int>(1, min(20, N - 1 - i))(rng);\n                int j = i + d;\n                swap(p[i], p[j]);\n            } else {\n                int l = uniform_int_distribution<int>(0, N - 1)(rng);\n                int r = uniform_int_distribution<int>(0, N - 1)(rng);\n                if (l > r) swap(l, r);\n                if (r - l >= 2) {\n                    int mid = uniform_int_distribution<int>(l + 1, r)(rng);\n                    rotate(p.begin() + l, p.begin() + mid, p.begin() + r + 1);\n                }\n            }\n        }\n    }\n\n    vector<int> guided_perturb_perm(const vector<int>& base) {\n        vector<int> p = base;\n\n        int ops = uniform_int_distribution<int>(2, 4)(rng);\n        for (int rep = 0; rep < ops; rep++) {\n            vector<int> depth;\n            eval_perm(p, nullptr, &depth);\n\n            auto bad_score = [&](int v) -> long long {\n                // high beauty but shallow => should go later\n                return 1LL * A[v] * (H - depth[v]) + 2LL * A[v];\n            };\n            auto support_score = [&](int v) -> long long {\n                // low beauty / high degree but already deep => should go earlier\n                long long raw = 1LL * (5 * degv[v] - 3 * A[v]);\n                if (raw < 0) raw = 0;\n                return raw * (depth[v] + 1) - (long long)(rad[v] / 10.0);\n            };\n\n            int typ = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (typ < 38) {\n                int best_i = -1;\n                long long best_s = LLONG_MIN;\n                for (int t = 0; t < 36; t++) {\n                    int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (i + 1 >= N) continue;\n                    int v = p[i];\n                    long long s = bad_score(v);\n                    if (s > best_s) {\n                        best_s = s;\n                        best_i = i;\n                    }\n                }\n                if (best_i != -1) {\n                    int span = min(N - 1 - best_i, uniform_int_distribution<int>(20, 160)(rng));\n                    int j = best_i + uniform_int_distribution<int>(1, max(1, span))(rng);\n                    random_insert_move(p, best_i, j);\n                }\n            } else if (typ < 76) {\n                int best_i = -1;\n                long long best_s = LLONG_MIN;\n                for (int t = 0; t < 36; t++) {\n                    int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (i <= 0) continue;\n                    int v = p[i];\n                    long long s = support_score(v);\n                    if (s > best_s) {\n                        best_s = s;\n                        best_i = i;\n                    }\n                }\n                if (best_i != -1) {\n                    int span = min(best_i, uniform_int_distribution<int>(20, 160)(rng));\n                    int j = best_i - uniform_int_distribution<int>(1, max(1, span))(rng);\n                    random_insert_move(p, best_i, j);\n                }\n            } else if (typ < 92) {\n                int bi = -1, si = -1;\n                long long best_bad = LLONG_MIN, best_sup = LLONG_MIN;\n                for (int t = 0; t < 40; t++) {\n                    int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                    int v = p[i];\n                    long long sb = bad_score(v) - 4LL * max(0, i - N / 2);\n                    if (i + 1 < N && sb > best_bad) {\n                        best_bad = sb;\n                        bi = i;\n                    }\n                    long long ss = support_score(v) - 3LL * max(0, N / 2 - i);\n                    if (i > 0 && ss > best_sup) {\n                        best_sup = ss;\n                        si = i;\n                    }\n                }\n                if (bi != -1 && si != -1 && bi < si) {\n                    swap(p[bi], p[si]);\n                } else {\n                    perturb_perm(p);\n                }\n            } else {\n                perturb_perm(p);\n            }\n        }\n\n        return p;\n    }\n\n    void greedy_polish_perm(vector<int>& perm, long long& score, double end_time) {\n        bool improved = true;\n        while (improved && elapsed() < end_time) {\n            improved = false;\n            for (int i = 0; i + 1 < N && elapsed() < end_time; i++) {\n                swap(perm[i], perm[i + 1]);\n                long long sc = score_of_perm(perm);\n                if (sc >= score) {\n                    if (sc > score) improved = true;\n                    score = sc;\n                } else {\n                    swap(perm[i], perm[i + 1]);\n                }\n            }\n        }\n    }\n\n    void local_search_perm(vector<int>& perm, long long& best_score, double end_time) {\n        vector<int> cur = perm;\n        long long cur_score = best_score;\n\n        vector<int> best = perm;\n        long long best_local = best_score;\n\n        const double T0 = 1200.0;\n        const double T1 = 5.0;\n\n        double local_start = elapsed();\n        double span = max(1e-9, end_time - local_start);\n\n        while (elapsed() < end_time) {\n            double prog = (elapsed() - local_start) / span;\n            prog = min(1.0, max(0.0, prog));\n            double temp = T0 * pow(T1 / T0, prog);\n\n            vector<int> cand = cur;\n            int type = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (type < 54) {\n                int i = uniform_int_distribution<int>(0, N - 1)(rng);\n                int v = cand[i];\n                int j;\n                if (A[v] >= 70 && i + 1 < N && uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(i + 1, N - 1)(rng);\n                } else if ((A[v] <= 30 || degv[v] >= 8) && i > 0 &&\n                           uniform_int_distribution<int>(0, 99)(rng) < 70) {\n                    j = uniform_int_distribution<int>(0, i - 1)(rng);\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                }\n                random_insert_move(cand, i, j);\n            } else if (type < 82) {\n                int i = uniform_int_distribution<int>(0, N - 2)(rng);\n                int j;\n                if (uniform_int_distribution<int>(0, 99)(rng) < 75) {\n                    j = i + 1;\n                } else {\n                    j = uniform_int_distribution<int>(0, N - 1)(rng);\n                    if (j == i) j = (j + 1) % N;\n                }\n                swap(cand[i], cand[j]);\n            } else if (type < 92) {\n                int l = uniform_int_distribution<int>(0, N - 1)(rng);\n                int r = uniform_int_distribution<int>(0, N - 1)(rng);\n                if (l > r) swap(l, r);\n                if (r - l >= 2) {\n                    int mid = uniform_int_distribution<int>(l + 1, r)(rng);\n                    rotate(cand.begin() + l, cand.begin() + mid, cand.begin() + r + 1);\n                }\n            } else {\n                perturb_perm(cand);\n            }\n\n            long long sc = score_of_perm(cand);\n            long long diff = sc - cur_score;\n\n            bool accept = false;\n            if (diff >= 0) {\n                accept = true;\n            } else {\n                double prob = exp((double)diff / temp);\n                double rr = uniform_real_distribution<double>(0.0, 1.0)(rng);\n                if (rr < prob) accept = true;\n            }\n\n            if (accept) {\n                cur.swap(cand);\n                cur_score = sc;\n                if (sc > best_local) {\n                    best_local = sc;\n                    best = cur;\n                }\n            }\n        }\n\n        greedy_polish_perm(best, best_local, min(end_time, elapsed() + 0.05));\n        perm = move(best);\n        best_score = best_local;\n    }\n\n    // =========================================================\n    // tree monotone improvement\n    // =========================================================\n    struct Info {\n        vector<int> depth, tin, tout, subH;\n        vector<long long> subA;\n        long long score = 0;\n    };\n\n    Info build_info(const vector<int>& parent) {\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) if (parent[v] != -1) ch[parent[v]].push_back(v);\n\n        Info info;\n        info.depth.assign(N, 0);\n        info.tin.assign(N, 0);\n        info.tout.assign(N, 0);\n        info.subH.assign(N, 0);\n        info.subA.assign(N, 0);\n        info.score = 0;\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v) -> void {\n            info.tin[v] = timer++;\n            info.subA[v] = A[v];\n            info.subH[v] = 0;\n            info.score += 1LL * (info.depth[v] + 1) * A[v];\n            for (int c : ch[v]) {\n                info.depth[c] = info.depth[v] + 1;\n                self(self, c);\n                info.subA[v] += info.subA[c];\n                info.subH[v] = max(info.subH[v], info.subH[c] + 1);\n            }\n            info.tout[v] = timer;\n        };\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                info.depth[v] = 0;\n                dfs(dfs, v);\n            }\n        }\n        return info;\n    }\n\n    static bool is_ancestor(const Info& info, int a, int b) {\n        return info.tin[a] <= info.tin[b] && info.tout[b] <= info.tout[a];\n    }\n\n    long long improve_tree(vector<int>& parent, double end_time) {\n        long long last_score = -1;\n\n        while (elapsed() < end_time) {\n            Info info = build_info(parent);\n            last_score = info.score;\n\n            long long best_gain = 0;\n            int best_u = -1, best_v = -1;\n            int best_nd = -1;\n            long long best_sub = -1;\n\n            auto eval_move = [&](int u, int v) {\n                if (parent[v] == u) return;\n                if (is_ancestor(info, v, u)) return;\n                if (info.depth[u] >= H) return;\n\n                int nd = info.depth[u] + 1;\n                if (nd <= info.depth[v]) return;\n                if (nd + info.subH[v] > H) return;\n\n                long long gain = 1LL * (nd - info.depth[v]) * info.subA[v];\n                if (gain > best_gain ||\n                    (gain == best_gain && nd > best_nd) ||\n                    (gain == best_gain && nd == best_nd && info.subA[v] > best_sub)) {\n                    best_gain = gain;\n                    best_u = u;\n                    best_v = v;\n                    best_nd = nd;\n                    best_sub = info.subA[v];\n                }\n            };\n\n            for (auto [a, b] : edges) {\n                eval_move(a, b);\n                eval_move(b, a);\n            }\n\n            if (best_gain <= 0) break;\n            parent[best_v] = best_u;\n        }\n\n        if (last_score == -1) last_score = build_info(parent).score;\n        return last_score;\n    }\n\n    void push_top_perm(vector<pair<long long, vector<int>>>& pool,\n                       long long score, const vector<int>& perm, int limit = 5) {\n        for (auto& e : pool) {\n            if (e.second == perm) {\n                if (score > e.first) e.first = score;\n                sort(pool.begin(), pool.end(), [&](auto& a, auto& b) { return a.first > b.first; });\n                return;\n            }\n        }\n        pool.push_back({score, perm});\n        sort(pool.begin(), pool.end(), [&](auto& a, auto& b) {\n            return a.first > b.first;\n        });\n        if ((int)pool.size() > limit) pool.resize(limit);\n    }\n\n    // =========================================================\n    // solve\n    // =========================================================\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            edges[i] = {u, v};\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        X.resize(N);\n        Y.resize(N);\n        for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n        st = chrono::steady_clock::now();\n\n        degv.assign(N, 0);\n        rad.assign(N, 0.0);\n        for (int v = 0; v < N; v++) {\n            degv[v] = (int)g[v].size();\n            double dx = X[v] - 500.0;\n            double dy = Y[v] - 500.0;\n            rad[v] = sqrt(dx * dx + dy * dy);\n        }\n\n        // 1) initial permutations\n        vector<pair<long long, vector<int>>> init;\n        for (int mode = 0; mode <= 3; mode++) {\n            auto p = make_initial_perm(mode);\n            long long sc = score_of_perm(p);\n            init.push_back({sc, move(p)});\n        }\n        while ((int)init.size() < 14 && elapsed() < 0.20) {\n            auto p = make_initial_perm(100);\n            long long sc = score_of_perm(p);\n            init.push_back({sc, move(p)});\n        }\n\n        sort(init.begin(), init.end(), [&](auto& a, auto& b) {\n            return a.first > b.first;\n        });\n\n        // 2) optimize top few deeply\n        vector<pair<long long, vector<int>>> topPerms;\n        long long best_perm_score = init[0].first;\n        vector<int> best_perm = init[0].second;\n\n        double perm_phase_end = 1.47;\n        int K = min<int>(3, init.size());\n\n        for (int i = 0; i < K && elapsed() < perm_phase_end; i++) {\n            vector<int> p = init[i].second;\n            long long sc = init[i].first;\n\n            double remaining = perm_phase_end - elapsed();\n            double slice_end = elapsed() + remaining / (K - i);\n\n            local_search_perm(p, sc, slice_end);\n            push_top_perm(topPerms, sc, p);\n\n            if (sc > best_perm_score) {\n                best_perm_score = sc;\n                best_perm = p;\n            }\n        }\n\n        if (topPerms.empty()) push_top_perm(topPerms, best_perm_score, best_perm);\n\n        // 3) restarts: best / elite / guided / fresh\n        while (elapsed() < 1.72) {\n            vector<int> p;\n            int typ = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (typ < 40) {\n                p = best_perm;\n                perturb_perm(p);\n            } else if (typ < 62 && !topPerms.empty()) {\n                int id = uniform_int_distribution<int>(0, (int)topPerms.size() - 1)(rng);\n                p = topPerms[id].second;\n                perturb_perm(p);\n            } else if (typ < 92) {\n                if (!topPerms.empty() && uniform_int_distribution<int>(0, 99)(rng) < 45) {\n                    int id = uniform_int_distribution<int>(0, (int)topPerms.size() - 1)(rng);\n                    p = guided_perturb_perm(topPerms[id].second);\n                } else {\n                    p = guided_perturb_perm(best_perm);\n                }\n            } else {\n                p = make_initial_perm(100);\n            }\n\n            long long sc = score_of_perm(p);\n            double end_time = min(1.72, elapsed() + 0.055);\n            local_search_perm(p, sc, end_time);\n            push_top_perm(topPerms, sc, p);\n\n            if (sc > best_perm_score) {\n                best_perm_score = sc;\n                best_perm = p;\n            }\n        }\n\n        // 4) tree improvement from top permutations\n        vector<int> best_parent(N, -1);\n        long long best_score = -1;\n\n        int TP = min<int>(3, topPerms.size());\n        for (int i = 0; i < TP && elapsed() < TL - 0.01; i++) {\n            vector<int> parent;\n            long long base_score = eval_perm(topPerms[i].second, &parent);\n\n            double rem = TL - 0.005 - elapsed();\n            double slice = max(0.0, rem / max(1, TP - i));\n            long long sc = improve_tree(parent, min(TL - 0.003, elapsed() + slice));\n\n            if (sc < base_score) sc = base_score;\n            if (sc > best_score) {\n                best_score = sc;\n                best_parent = move(parent);\n            }\n        }\n\n        if (best_score < 0) {\n            best_score = eval_perm(best_perm, &best_parent);\n        }\n\n        improve_tree(best_parent, TL - 0.001);\n\n        for (int v = 0; v < N; v++) {\n            if (v) cout << ' ';\n            cout << best_parent[v];\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int INF = 1e9;\nstatic constexpr int NMAX = 20;\nstatic constexpr int FMAX = 80;\n\nstruct XorShift {\n    uint64_t x = 88172645463393265ULL;\n    XorShift(uint64_t seed = 0) {\n        x ^= seed + 0x9e3779b97f4a7c15ULL;\n        next();\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n = 0) : n(n), p(n), sz(n, 1) {\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\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\nstatic inline int popcount64(uint64_t x) {\n    return __builtin_popcountll(x);\n}\n\nstatic uint64_t zob[NMAX][NMAX][3];\nstatic bool zob_inited = false;\n\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\nstatic void init_zob() {\n    if (zob_inited) return;\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < NMAX; i++) {\n        for (int j = 0; j < NMAX; j++) {\n            for (int t = 0; t < 3; t++) {\n                seed = splitmix64(seed + 0x9e3779b97f4a7c15ULL);\n                zob[i][j][t] = seed;\n            }\n        }\n    }\n    zob_inited = true;\n}\n\nstatic uint64_t hash_board(const vector<string>& B) {\n    uint64_t h = 0;\n    for (int i = 0; i < (int)B.size(); i++) {\n        for (int j = 0; j < (int)B[i].size(); j++) {\n            int t = 0;\n            if (B[i][j] == 'x') t = 1;\n            else if (B[i][j] == 'o') t = 2;\n            h ^= zob[i][j][t];\n        }\n    }\n    return h;\n}\n\nstruct Analysis {\n    int N = 0, P = 0, F = 0;\n    vector<pair<int,int>> oni;\n    vector<int> firstRowFuku, lastRowFuku;\n    vector<int> firstColFuku, lastColFuku;\n    vector<vector<int>> reqDepth;\n    vector<vector<int>> opts;\n    vector<int> minDepth;\n    bool allSafe = true;\n    int guaranteedTail = INF;\n    int greedyTail = INF;\n};\n\nstatic int greedy_assign_upper_bound(const Analysis& A) {\n    if (A.P == 0) return 0;\n    int P = A.P, F = A.F;\n\n    vector<int> order(P);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if ((int)A.opts[a].size() != (int)A.opts[b].size())\n            return A.opts[a].size() < A.opts[b].size();\n        if (A.minDepth[a] != A.minDepth[b])\n            return A.minDepth[a] > A.minDepth[b];\n        return a < b;\n    });\n\n    vector<int> mx(F, 0);\n    for (int p : order) {\n        int bestF = -1;\n        tuple<int,int,int,int> bestKey = {INF, INF, INF, INF};\n        for (int f : A.opts[p]) {\n            int d = A.reqDepth[p][f];\n            int inc = max(0, d - mx[f]);\n            auto key = make_tuple(inc, d, mx[f], f);\n            if (key < bestKey) {\n                bestKey = key;\n                bestF = f;\n            }\n        }\n        if (bestF == -1) return INF;\n        mx[bestF] = max(mx[bestF], A.reqDepth[p][bestF]);\n    }\n\n    int cost = 0;\n    for (int f = 0; f < F; f++) cost += 2 * mx[f];\n    return cost;\n}\n\nstatic Analysis analyze_board(const vector<string>& B) {\n    int N = (int)B.size();\n    int F = 4 * N;\n\n    Analysis A;\n    A.N = N;\n    A.F = F;\n    A.firstRowFuku.assign(N, N);\n    A.lastRowFuku.assign(N, -1);\n    A.firstColFuku.assign(N, N);\n    A.lastColFuku.assign(N, -1);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (B[i][j] == 'o') {\n                A.firstRowFuku[i] = min(A.firstRowFuku[i], j);\n                A.lastRowFuku[i] = max(A.lastRowFuku[i], j);\n                A.firstColFuku[j] = min(A.firstColFuku[j], i);\n                A.lastColFuku[j] = max(A.lastColFuku[j], i);\n            } else if (B[i][j] == 'x') {\n                A.oni.push_back({i, j});\n            }\n        }\n    }\n\n    A.P = (int)A.oni.size();\n    A.reqDepth.assign(A.P, vector<int>(F, INF));\n    A.opts.assign(A.P, {});\n    A.minDepth.assign(A.P, INF);\n\n    auto idL = [&](int i) { return i; };\n    auto idR = [&](int i) { return N + i; };\n    auto idU = [&](int j) { return 2 * N + j; };\n    auto idD = [&](int j) { return 3 * N + j; };\n\n    A.allSafe = true;\n    A.guaranteedTail = 0;\n\n    for (int p = 0; p < A.P; p++) {\n        auto [i, j] = A.oni[p];\n\n        if (j < A.firstRowFuku[i]) {\n            int f = idL(i), d = j + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (j > A.lastRowFuku[i]) {\n            int f = idR(i), d = N - j;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i < A.firstColFuku[j]) {\n            int f = idU(j), d = i + 1;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n        if (i > A.lastColFuku[j]) {\n            int f = idD(j), d = N - i;\n            A.reqDepth[p][f] = d;\n            A.opts[p].push_back(f);\n            A.minDepth[p] = min(A.minDepth[p], d);\n        }\n\n        if (A.opts[p].empty()) {\n            A.allSafe = false;\n            A.guaranteedTail = INF;\n        } else {\n            A.guaranteedTail += 2 * A.minDepth[p];\n        }\n    }\n\n    A.greedyTail = A.allSafe ? greedy_assign_upper_bound(A) : INF;\n    return A;\n}\n\nstruct MacroAction {\n    char dir;\n    int idx;\n    int k;\n    int removed;\n};\n\nstatic vector<MacroAction> generate_actions(const vector<string>& B, const Analysis& A, bool includeReposition = true) {\n    int N = A.N;\n    vector<MacroAction> res;\n\n    for (int i = 0; i < N; i++) {\n        int limL = A.firstRowFuku[i];\n        if (limL > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limL; k++) {\n                if (B[i][k - 1] == 'x') acc++;\n                if (acc > 0) res.push_back({'L', i, k, acc});\n            }\n        }\n        int limR = (A.lastRowFuku[i] == -1 ? N : N - 1 - A.lastRowFuku[i]);\n        if (limR > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limR; k++) {\n                if (B[i][N - k] == 'x') acc++;\n                if (acc > 0) res.push_back({'R', i, k, acc});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        int limU = A.firstColFuku[j];\n        if (limU > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limU; k++) {\n                if (B[k - 1][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'U', j, k, acc});\n            }\n        }\n        int limD = (A.lastColFuku[j] == -1 ? N : N - 1 - A.lastColFuku[j]);\n        if (limD > 0) {\n            int acc = 0;\n            for (int k = 1; k <= limD; k++) {\n                if (B[N - k][j] == 'x') acc++;\n                if (acc > 0) res.push_back({'D', j, k, acc});\n            }\n        }\n    }\n\n    if (includeReposition) {\n        for (int i = 0; i < N; i++) {\n            if (B[i][0] == '.') res.push_back({'L', i, 1, 0});\n            if (B[i][N - 1] == '.') res.push_back({'R', i, 1, 0});\n        }\n        for (int j = 0; j < N; j++) {\n            if (B[0][j] == '.') res.push_back({'U', j, 1, 0});\n            if (B[N - 1][j] == '.') res.push_back({'D', j, 1, 0});\n        }\n    }\n\n    return res;\n}\n\nstatic vector<string> apply_macro(const vector<string>& B, char dir, int idx, int k) {\n    int N = (int)B.size();\n    vector<string> C = B;\n\n    if (dir == 'L') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j] = B[idx][j + k];\n        C[idx] = t;\n    } else if (dir == 'R') {\n        string t(N, '.');\n        for (int j = 0; j + k < N; j++) t[j + k] = B[idx][j];\n        C[idx] = t;\n    } else if (dir == 'U') {\n        for (int i = 0; i + k < N; i++) C[i][idx] = B[i + k][idx];\n        for (int i = N - k; i < N; i++) C[i][idx] = '.';\n    } else {\n        for (int i = 0; i + k < N; i++) C[i + k][idx] = B[i][idx];\n        for (int i = 0; i < k; i++) C[i][idx] = '.';\n    }\n    return C;\n}\n\n// ---------- Tail solver ----------\n\nstruct Cand {\n    uint64_t mask;\n    int cost;\n    int facility;\n    int depth;\n};\n\nstatic vector<Cand> reduce_candidates(vector<Cand> v) {\n    if (v.empty()) return v;\n\n    sort(v.begin(), v.end(), [](const Cand& a, const Cand& b) {\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> dedup;\n    for (int i = 0; i < (int)v.size();) {\n        int j = i + 1;\n        Cand best = v[i];\n        while (j < (int)v.size() && v[j].mask == v[i].mask) {\n            if (v[j].cost < best.cost) best = v[j];\n            j++;\n        }\n        if (best.mask) dedup.push_back(best);\n        i = j;\n    }\n\n    sort(dedup.begin(), dedup.end(), [](const Cand& a, const Cand& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        int pa = popcount64(a.mask), pb = popcount64(b.mask);\n        if (pa != pb) return pa > pb;\n        if (a.mask != b.mask) return a.mask < b.mask;\n        if (a.facility != b.facility) return a.facility < b.facility;\n        return a.depth < b.depth;\n    });\n\n    vector<Cand> res;\n    for (const auto& c : dedup) {\n        bool dominated = false;\n        for (const auto& d : res) {\n            if (d.cost <= c.cost && (c.mask & ~d.mask) == 0ULL) {\n                dominated = true;\n                break;\n            }\n        }\n        if (!dominated) res.push_back(c);\n    }\n    return res;\n}\n\nstruct SolveResult {\n    vector<int> depth;\n    int cost = INF;\n};\n\nstruct FacilityOption {\n    uint64_t mask;\n    int cost;\n    int depth;\n};\n\nstatic SolveResult canonicalize_and_descent(\n    int m, int F,\n    const vector<Cand>& cands,\n    const vector<int>& selectedIds\n) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> curPos(F, 0);\n    for (int id : selectedIds) {\n        int f = cands[id].facility;\n        int d = cands[id].depth;\n        for (int p = 0; p < (int)opts[f].size(); p++) {\n            if (opts[f][p].depth == d) {\n                curPos[f] = max(curPos[f], p);\n                break;\n            }\n        }\n    }\n\n    vector<int> coverCnt(m, 0);\n    auto addMask = [&](uint64_t mask, int delta) {\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverCnt[b] += delta;\n            mask &= mask - 1;\n        }\n    };\n    for (int f = 0; f < F; f++) addMask(opts[f][curPos[f]].mask, +1);\n\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int f = 0; f < F; f++) {\n            int old = curPos[f];\n            if (old == 0) continue;\n            addMask(opts[f][old].mask, -1);\n\n            int best = old;\n            for (int p = 0; p <= old; p++) {\n                uint64_t mask = opts[f][p].mask;\n                bool ok = true;\n                for (int i = 0; i < m; i++) {\n                    int c = coverCnt[i] + ((mask >> i) & 1ULL);\n                    if (c == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (ok) {\n                    best = p;\n                    break;\n                }\n            }\n\n            curPos[f] = best;\n            addMask(opts[f][curPos[f]].mask, +1);\n            if (curPos[f] != old) improved = true;\n        }\n    }\n\n    vector<int> depth(F, 0);\n    int cost = 0;\n    for (int f = 0; f < F; f++) {\n        depth[f] = opts[f][curPos[f]].depth;\n        cost += opts[f][curPos[f]].cost;\n    }\n    return {depth, cost};\n}\n\nstatic SolveResult greedy_component_heuristic(int m, int F, const vector<Cand>& cands) {\n    vector<vector<FacilityOption>> opts(F);\n    for (int f = 0; f < F; f++) opts[f].push_back({0ULL, 0, 0});\n    for (const auto& c : cands) opts[c.facility].push_back({c.mask, c.cost, c.depth});\n\n    for (int f = 0; f < F; f++) {\n        auto& v = opts[f];\n        sort(v.begin(), v.end(), [](const FacilityOption& a, const FacilityOption& b) {\n            if (a.depth != b.depth) return a.depth < b.depth;\n            return a.cost < b.cost;\n        });\n        vector<FacilityOption> nv;\n        for (auto x : v) {\n            if (nv.empty() || nv.back().depth != x.depth) nv.push_back(x);\n            else if (x.cost < nv.back().cost) nv.back() = x;\n        }\n        v.swap(nv);\n    }\n\n    vector<int> pos(F, 0);\n    uint64_t full = (m == 64 ? ~0ULL : ((1ULL << m) - 1ULL));\n    uint64_t covered = 0;\n\n    while (covered != full) {\n        int bf = -1, bp = -1, bestInc = INF, bestGain = -1, bestFinal = INF;\n        for (int f = 0; f < F; f++) {\n            for (int p = pos[f] + 1; p < (int)opts[f].size(); p++) {\n                uint64_t newbits = opts[f][p].mask & ~covered;\n                int gain = popcount64(newbits);\n                if (gain == 0) continue;\n                int inc = opts[f][p].cost - opts[f][pos[f]].cost;\n                if (bf == -1 ||\n                    1LL * inc * bestGain < 1LL * bestInc * gain ||\n                    (1LL * inc * bestGain == 1LL * bestInc * gain &&\n                     (gain > bestGain ||\n                      (gain == bestGain && opts[f][p].cost < bestFinal)))) {\n                    bf = f;\n                    bp = p;\n                    bestInc = inc;\n                    bestGain = gain;\n                    bestFinal = opts[f][p].cost;\n                }\n            }\n        }\n        if (bf == -1) break;\n        pos[bf] = bp;\n        covered |= opts[bf][bp].mask;\n    }\n\n    vector<int> selected;\n    for (int f = 0; f < F; f++) {\n        if (pos[f] == 0) continue;\n        int d = opts[f][pos[f]].depth;\n        for (int id = 0; id < (int)cands.size(); id++) {\n            if (cands[id].facility == f && cands[id].depth == d) {\n                selected.push_back(id);\n                break;\n            }\n        }\n    }\n    return canonicalize_and_descent(m, F, cands, selected);\n}\n\nstatic SolveResult exact_small_component(int m, int F, const vector<Cand>& cands) {\n    vector<vector<int>> coverByPoint(m);\n    for (int id = 0; id < (int)cands.size(); id++) {\n        uint64_t mask = cands[id].mask;\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            coverByPoint[b].push_back(id);\n            mask &= mask - 1;\n        }\n    }\n\n    for (int i = 0; i < m; i++) {\n        sort(coverByPoint[i].begin(), coverByPoint[i].end(), [&](int a, int b) {\n            int pa = popcount64(cands[a].mask), pb = popcount64(cands[b].mask);\n            if (pa != pb) return pa > pb;\n            if (cands[a].cost != cands[b].cost) return cands[a].cost < cands[b].cost;\n            return a < b;\n        });\n    }\n\n    uint32_t FULL = (m == 32 ? 0xFFFFFFFFu : ((1u << m) - 1u));\n    const uint16_t UNK = 65535;\n\n    vector<uint16_t> memo((size_t)FULL + 1, UNK);\n    vector<uint16_t> choice((size_t)FULL + 1, UNK);\n\n    function<uint16_t(uint32_t)> dfs = [&](uint32_t mask) -> uint16_t {\n        if (mask == 0) return 0;\n        uint16_t& ret = memo[mask];\n        if (ret != UNK) return ret;\n\n        int pivot = -1, bestCnt = INF;\n        uint32_t tmp = mask;\n        while (tmp) {\n            int b = __builtin_ctz(tmp);\n            int cnt = (int)coverByPoint[b].size();\n            if (cnt < bestCnt) {\n                bestCnt = cnt;\n                pivot = b;\n            }\n            tmp &= tmp - 1;\n        }\n\n        uint16_t best = UNK, bestId = UNK;\n        for (int id : coverByPoint[pivot]) {\n            uint32_t nmask = mask & ~(uint32_t)cands[id].mask;\n            uint16_t sub = dfs(nmask);\n            uint16_t val = (uint16_t)(sub + cands[id].cost);\n            if (best == UNK || val < best) {\n                best = val;\n                bestId = (uint16_t)id;\n            }\n        }\n        ret = best;\n        choice[mask] = bestId;\n        return ret;\n    };\n\n    (void)dfs(FULL);\n\n    vector<int> selected;\n    uint32_t mask = FULL;\n    while (mask) {\n        int id = choice[mask];\n        selected.push_back(id);\n        mask &= ~(uint32_t)cands[id].mask;\n    }\n    return canonicalize_and_descent(m, F, cands, selected);\n}\n\nstatic SolveResult solve_setcover_tail(const Analysis& A) {\n    SolveResult ret;\n    ret.depth.assign(A.F, 0);\n    if (!A.allSafe) return ret;\n    if (A.P == 0) {\n        ret.cost = 0;\n        return ret;\n    }\n\n    vector<Cand> gcands;\n    for (int f = 0; f < A.F; f++) {\n        vector<pair<int,int>> v;\n        for (int p = 0; p < A.P; p++) if (A.reqDepth[p][f] < INF) v.push_back({A.reqDepth[p][f], p});\n        sort(v.begin(), v.end());\n\n        uint64_t mask = 0;\n        for (int i = 0; i < (int)v.size();) {\n            int d = v[i].first;\n            while (i < (int)v.size() && v[i].first == d) {\n                mask |= (1ULL << v[i].second);\n                i++;\n            }\n            gcands.push_back({mask, 2 * d, f, d});\n        }\n    }\n\n    gcands = reduce_candidates(gcands);\n\n    DSU dsu(A.P);\n    for (const auto& c : gcands) {\n        if (popcount64(c.mask) <= 1) continue;\n        int first = __builtin_ctzll(c.mask);\n        uint64_t tmp = c.mask & (c.mask - 1);\n        while (tmp) {\n            int b = __builtin_ctzll(tmp);\n            dsu.unite(first, b);\n            tmp &= tmp - 1;\n        }\n    }\n\n    unordered_map<int, vector<int>> groups;\n    for (int p = 0; p < A.P; p++) groups[dsu.find(p)].push_back(p);\n\n    vector<int> finalDepth(A.F, 0);\n    int finalCost = 0;\n\n    for (auto& [root, pts] : groups) {\n        int m = (int)pts.size();\n        vector<int> g2l(A.P, -1);\n        for (int i = 0; i < m; i++) g2l[pts[i]] = i;\n\n        uint64_t compMask = 0;\n        for (int p : pts) compMask |= (1ULL << p);\n\n        vector<Cand> lcands;\n        for (const auto& c : gcands) {\n            if ((c.mask & compMask) == 0ULL) continue;\n            if ((c.mask & ~compMask) != 0ULL) continue;\n\n            uint64_t lmask = 0;\n            uint64_t tmp = c.mask;\n            while (tmp) {\n                int gp = __builtin_ctzll(tmp);\n                lmask |= (1ULL << g2l[gp]);\n                tmp &= tmp - 1;\n            }\n            lcands.push_back({lmask, c.cost, c.facility, c.depth});\n        }\n\n        lcands = reduce_candidates(lcands);\n\n        SolveResult comp;\n        if (m <= 23) comp = exact_small_component(m, A.F, lcands);\n        else comp = greedy_component_heuristic(m, A.F, lcands);\n\n        for (int f = 0; f < A.F; f++) finalDepth[f] = max(finalDepth[f], comp.depth[f]);\n        finalCost += comp.cost;\n    }\n\n    ret.depth = std::move(finalDepth);\n    ret.cost = finalCost;\n    return ret;\n}\n\nstatic vector<int> build_individual_fallback_depth(const Analysis& A) {\n    vector<int> depth(A.F, 0);\n    for (int p = 0; p < A.P; p++) {\n        int bestF = -1, bestD = INF;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] < bestD) {\n                bestD = A.reqDepth[p][f];\n                bestF = f;\n            }\n        }\n        if (bestF != -1) depth[bestF] = max(depth[bestF], bestD);\n    }\n    return depth;\n}\n\nstatic int depth_cost(const vector<int>& depthByFacility) {\n    int s = 0;\n    for (int d : depthByFacility) s += 2 * d;\n    return s;\n}\n\nstatic bool validate_depth_solution(const Analysis& A, const vector<int>& depthByFacility) {\n    if (!A.allSafe) return false;\n    for (int p = 0; p < A.P; p++) {\n        bool ok = false;\n        for (int f : A.opts[p]) {\n            if (A.reqDepth[p][f] <= depthByFacility[f]) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n    return true;\n}\n\nstruct MemoVal {\n    int cost = INF;\n    array<uint8_t, FMAX> depth{};\n};\n\nstatic MemoVal solve_tail_memoized(const vector<string>& board, unordered_map<uint64_t, MemoVal>& memo) {\n    uint64_t h = hash_board(board);\n    auto it = memo.find(h);\n    if (it != memo.end()) return it->second;\n\n    Analysis A = analyze_board(board);\n    MemoVal mv;\n\n    if (!A.allSafe) {\n        mv.cost = INF;\n        memo[h] = mv;\n        return mv;\n    }\n\n    SolveResult res = solve_setcover_tail(A);\n    if (!validate_depth_solution(A, res.depth)) {\n        res.depth = build_individual_fallback_depth(A);\n        res.cost = depth_cost(res.depth);\n    }\n\n    mv.cost = res.cost;\n    mv.depth.fill(0);\n    for (int f = 0; f < A.F; f++) mv.depth[f] = (uint8_t)res.depth[f];\n    memo[h] = mv;\n    return mv;\n}\n\nstatic vector<pair<char,int>> depth_to_ops(const vector<int>& depthByFacility, int N) {\n    vector<pair<char,int>> ans;\n    for (int f = 0; f < (int)depthByFacility.size(); f++) {\n        int k = depthByFacility[f];\n        if (k == 0) continue;\n        if (f < N) {\n            int i = f;\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n        } else if (f < 2 * N) {\n            int i = f - N;\n            for (int t = 0; t < k; t++) ans.push_back({'R', i});\n            for (int t = 0; t < k; t++) ans.push_back({'L', i});\n        } else if (f < 3 * N) {\n            int j = f - 2 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n        } else {\n            int j = f - 3 * N;\n            for (int t = 0; t < k; t++) ans.push_back({'D', j});\n            for (int t = 0; t < k; t++) ans.push_back({'U', j});\n        }\n    }\n    return ans;\n}\n\n// ---------- Search ----------\n\nstruct State {\n    vector<string> board;\n    vector<pair<char,int>> ops;\n    int g = 0;\n    int total = INF;\n    MemoVal tail;\n    uint64_t h = 0;\n};\n\nstruct ChildQuick {\n    int parent = -1;\n    array<MacroAction, 2> macs{};\n    int mlen = 0;\n    int removedSum = 0;\n    int addCost = 0;\n    vector<string> board;\n    int quick = INF;\n    int guaranteed = INF;\n    int g2 = INF;\n    uint64_t h = 0;\n    uint64_t key = 0;\n};\n\nstruct ChildFull {\n    vector<string> board;\n    vector<pair<char,int>> ops;\n    int g = INF;\n    int total = INF;\n    MemoVal tail;\n    uint64_t h = 0;\n};\n\nstatic State beam_search_restart(\n    const State& init,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    XorShift& rng,\n    chrono::steady_clock::time_point deadline,\n    bool randomized,\n    int legalLimit\n) {\n    const int BEAM_WIDTH = randomized ? 4 : 6;\n    const int PER_STATE_KEEP = randomized ? 9 : 12;\n    const int GLOBAL_EXACT = randomized ? 20 : 28;\n    const int REP1_KEEP = randomized ? 4 : 5;\n    const int REP2_KEEP = 5;\n\n    State best = init;\n    vector<State> beam = {init};\n\n    unordered_map<uint64_t, int> seenBestG;\n    seenBestG.reserve(4096);\n    seenBestG[init.h] = init.g;\n\n    struct Rep1 {\n        MacroAction a1;\n        vector<string> b1;\n        int g1, quick1, guar1;\n        uint64_t key;\n    };\n\n    while (chrono::steady_clock::now() < deadline) {\n        vector<ChildQuick> quicks;\n        quicks.reserve(1024);\n\n        for (int si = 0; si < (int)beam.size(); si++) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            const State& st = beam[si];\n            Analysis A = analyze_board(st.board);\n            if (!A.allSafe || A.P == 0) continue;\n\n            auto acts = generate_actions(st.board, A, true);\n            if (acts.empty()) continue;\n\n            vector<ChildQuick> local;\n            local.reserve(acts.size() + 64);\n            vector<Rep1> rep1s;\n\n            auto add_child = [&](const vector<string>& nb, uint64_t hh, int g2, int quick, int guar,\n                                 const array<MacroAction,2>& macs, int mlen, int removedSum, int addCost, uint64_t key) {\n                ChildQuick cq;\n                cq.parent = si;\n                cq.macs = macs;\n                cq.mlen = mlen;\n                cq.removedSum = removedSum;\n                cq.addCost = addCost;\n                cq.board = nb;\n                cq.g2 = g2;\n                cq.quick = quick;\n                cq.guaranteed = guar;\n                cq.h = hh;\n                cq.key = key;\n                local.push_back(std::move(cq));\n            };\n\n            for (const auto& act : acts) {\n                if (st.g + act.k > legalLimit) continue;\n\n                auto nb = apply_macro(st.board, act.dir, act.idx, act.k);\n                uint64_t hh = hash_board(nb);\n                int g2 = st.g + act.k;\n\n                auto itSeen = seenBestG.find(hh);\n                if (itSeen != seenBestG.end() && itSeen->second <= g2) continue;\n\n                Analysis na = analyze_board(nb);\n                if (!na.allSafe) continue;\n                if (g2 + na.guaranteedTail > legalLimit) continue;\n\n                array<MacroAction,2> macs{};\n                macs[0] = act;\n                add_child(nb, hh, g2,\n                          g2 + min(na.greedyTail, na.guaranteedTail),\n                          g2 + na.guaranteedTail,\n                          macs, 1, act.removed, act.k,\n                          randomized ? rng.next() : 0);\n\n                if (act.removed == 0 && act.k == 1) {\n                    rep1s.push_back({act, std::move(nb), g2,\n                                     g2 + min(na.greedyTail, na.guaranteedTail),\n                                     g2 + na.guaranteedTail,\n                                     randomized ? rng.next() : 0});\n                }\n            }\n\n            sort(rep1s.begin(), rep1s.end(), [&](const Rep1& a, const Rep1& b) {\n                if (a.quick1 != b.quick1) return a.quick1 < b.quick1;\n                if (a.guar1 != b.guar1) return a.guar1 < b.guar1;\n                if (randomized && a.key != b.key) return a.key < b.key;\n                if (a.a1.dir != b.a1.dir) return a.a1.dir < b.a1.dir;\n                return a.a1.idx < b.a1.idx;\n            });\n            if ((int)rep1s.size() > REP1_KEEP) rep1s.resize(REP1_KEEP);\n\n            for (auto& r1 : rep1s) {\n                if (chrono::steady_clock::now() >= deadline) break;\n                Analysis A1 = analyze_board(r1.b1);\n                if (!A1.allSafe || A1.P == 0) continue;\n\n                auto acts2 = generate_actions(r1.b1, A1, false);\n                vector<ChildQuick> loc2;\n                loc2.reserve(acts2.size());\n\n                for (const auto& a2 : acts2) {\n                    if (a2.removed <= 0) continue;\n                    if (r1.g1 + a2.k > legalLimit) continue;\n\n                    auto b2 = apply_macro(r1.b1, a2.dir, a2.idx, a2.k);\n                    uint64_t hh2 = hash_board(b2);\n                    int g2 = r1.g1 + a2.k;\n\n                    auto itSeen = seenBestG.find(hh2);\n                    if (itSeen != seenBestG.end() && itSeen->second <= g2) continue;\n\n                    Analysis A2 = analyze_board(b2);\n                    if (!A2.allSafe) continue;\n                    if (g2 + A2.guaranteedTail > legalLimit) continue;\n\n                    ChildQuick cq;\n                    cq.parent = si;\n                    cq.macs[0] = r1.a1;\n                    cq.macs[1] = a2;\n                    cq.mlen = 2;\n                    cq.removedSum = a2.removed;\n                    cq.addCost = 1 + a2.k;\n                    cq.board = std::move(b2);\n                    cq.g2 = g2;\n                    cq.quick = g2 + min(A2.greedyTail, A2.guaranteedTail);\n                    cq.guaranteed = g2 + A2.guaranteedTail;\n                    cq.h = hh2;\n                    cq.key = randomized ? rng.next() : 0;\n                    loc2.push_back(std::move(cq));\n                }\n\n                sort(loc2.begin(), loc2.end(), [&](const ChildQuick& a, const ChildQuick& b) {\n                    if (a.quick != b.quick) return a.quick < b.quick;\n                    if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n                    long long lhs = 1LL * a.removedSum * b.addCost;\n                    long long rhs = 1LL * b.removedSum * a.addCost;\n                    if (lhs != rhs) return lhs > rhs;\n                    if (a.addCost != b.addCost) return a.addCost < b.addCost;\n                    if (randomized && a.key != b.key) return a.key < b.key;\n                    return a.h < b.h;\n                });\n                if ((int)loc2.size() > REP2_KEEP) loc2.resize(REP2_KEEP);\n                for (auto& x : loc2) local.push_back(std::move(x));\n            }\n\n            sort(local.begin(), local.end(), [&](const ChildQuick& a, const ChildQuick& b) {\n                if (a.quick != b.quick) return a.quick < b.quick;\n                if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n                if ((a.removedSum == 0) != (b.removedSum == 0)) return a.removedSum > b.removedSum;\n                long long lhs = 1LL * a.removedSum * b.addCost;\n                long long rhs = 1LL * b.removedSum * a.addCost;\n                if (lhs != rhs) return lhs > rhs;\n                if (a.addCost != b.addCost) return a.addCost < b.addCost;\n                if (randomized && a.key != b.key) return a.key < b.key;\n                return a.h < b.h;\n            });\n\n            if ((int)local.size() > PER_STATE_KEEP) local.resize(PER_STATE_KEEP);\n            for (auto& x : local) quicks.push_back(std::move(x));\n        }\n\n        if (quicks.empty()) break;\n\n        sort(quicks.begin(), quicks.end(), [&](const ChildQuick& a, const ChildQuick& b) {\n            if (a.quick != b.quick) return a.quick < b.quick;\n            if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n            if ((a.removedSum == 0) != (b.removedSum == 0)) return a.removedSum > b.removedSum;\n            long long lhs = 1LL * a.removedSum * b.addCost;\n            long long rhs = 1LL * b.removedSum * a.addCost;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.addCost != b.addCost) return a.addCost < b.addCost;\n            if (randomized && a.key != b.key) return a.key < b.key;\n            return a.h < b.h;\n        });\n\n        if ((int)quicks.size() > GLOBAL_EXACT) quicks.resize(GLOBAL_EXACT);\n\n        unordered_map<uint64_t, ChildFull> uniq;\n        uniq.reserve(quicks.size() * 2 + 1);\n\n        for (auto& cq : quicks) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            MemoVal tail = solve_tail_memoized(cq.board, tailMemo);\n            if (tail.cost >= INF) continue;\n            int total = cq.g2 + tail.cost;\n            if (total > legalLimit) continue;\n\n            ChildFull cf;\n            cf.board = std::move(cq.board);\n            cf.ops = beam[cq.parent].ops;\n            for (int m = 0; m < cq.mlen; m++) {\n                for (int t = 0; t < cq.macs[m].k; t++) {\n                    cf.ops.push_back({cq.macs[m].dir, cq.macs[m].idx});\n                }\n            }\n            cf.g = cq.g2;\n            cf.total = total;\n            cf.tail = tail;\n            cf.h = cq.h;\n\n            auto it = uniq.find(cf.h);\n            if (it == uniq.end() || cf.total < it->second.total || (cf.total == it->second.total && cf.g < it->second.g)) {\n                uniq[cf.h] = std::move(cf);\n            }\n        }\n\n        if (uniq.empty()) break;\n\n        vector<State> nextBeam;\n        nextBeam.reserve(uniq.size());\n        for (auto& [h, cf] : uniq) {\n            State st;\n            st.board = std::move(cf.board);\n            st.ops = std::move(cf.ops);\n            st.g = cf.g;\n            st.total = cf.total;\n            st.tail = cf.tail;\n            st.h = cf.h;\n            nextBeam.push_back(std::move(st));\n        }\n\n        sort(nextBeam.begin(), nextBeam.end(), [&](const State& a, const State& b) {\n            if (a.total != b.total) return a.total < b.total;\n            if (a.g != b.g) return a.g < b.g;\n            return a.h < b.h;\n        });\n\n        if ((int)nextBeam.size() > BEAM_WIDTH) nextBeam.resize(BEAM_WIDTH);\n\n        for (const auto& st : nextBeam) {\n            auto it = seenBestG.find(st.h);\n            if (it == seenBestG.end() || st.g < it->second) seenBestG[st.h] = st.g;\n            if (st.total < best.total || (st.total == best.total && st.g < best.g)) {\n                best = st;\n            }\n        }\n\n        beam = std::move(nextBeam);\n    }\n\n    return best;\n}\n\nstatic void exact_two_step_descent(\n    State& best,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    XorShift& rng,\n    chrono::steady_clock::time_point deadline,\n    int legalLimit\n) {\n    while (chrono::steady_clock::now() < deadline) {\n        Analysis A0 = analyze_board(best.board);\n        if (!A0.allSafe || A0.P == 0) break;\n\n        struct C1 {\n            MacroAction act1;\n            vector<string> b1;\n            int g1, quick1, guar1;\n            uint64_t key;\n        };\n\n        auto acts1 = generate_actions(best.board, A0, true);\n        if (acts1.empty()) break;\n\n        vector<C1> firsts;\n        firsts.reserve(acts1.size());\n\n        for (const auto& a1 : acts1) {\n            if (best.g + a1.k > legalLimit) continue;\n            auto b1 = apply_macro(best.board, a1.dir, a1.idx, a1.k);\n            Analysis A1 = analyze_board(b1);\n            if (!A1.allSafe) continue;\n            if (best.g + a1.k + A1.guaranteedTail > legalLimit) continue;\n            firsts.push_back({a1, std::move(b1),\n                              best.g + a1.k,\n                              best.g + a1.k + min(A1.greedyTail, A1.guaranteedTail),\n                              best.g + a1.k + A1.guaranteedTail,\n                              rng.next()});\n        }\n\n        if (firsts.empty()) break;\n\n        sort(firsts.begin(), firsts.end(), [&](const C1& a, const C1& b) {\n            if (a.quick1 != b.quick1) return a.quick1 < b.quick1;\n            if (a.guar1 != b.guar1) return a.guar1 < b.guar1;\n            if ((a.act1.removed == 0) != (b.act1.removed == 0)) return a.act1.removed > b.act1.removed;\n            long long lhs = 1LL * a.act1.removed * b.act1.k;\n            long long rhs = 1LL * b.act1.removed * a.act1.k;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.act1.k != b.act1.k) return a.act1.k < b.act1.k;\n            return a.key < b.key;\n        });\n\n        if ((int)firsts.size() > 8) firsts.resize(8);\n\n        int bestTotal = best.total;\n        int chosenI = -1, chosenJ = -1;\n        MemoVal chosenTail;\n        vector<string> chosenBoard;\n        MacroAction chosenA1{}, chosenA2{};\n        int chosenG = -1;\n\n        for (int i = 0; i < (int)firsts.size(); i++) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            MemoVal tail1 = solve_tail_memoized(firsts[i].b1, tailMemo);\n            if (tail1.cost < INF) {\n                int total1 = firsts[i].g1 + tail1.cost;\n                if (total1 < bestTotal) {\n                    bestTotal = total1;\n                    chosenI = i;\n                    chosenJ = -1;\n                    chosenTail = tail1;\n                    chosenBoard = firsts[i].b1;\n                    chosenA1 = firsts[i].act1;\n                    chosenG = firsts[i].g1;\n                }\n            }\n\n            Analysis A1 = analyze_board(firsts[i].b1);\n            if (!A1.allSafe || A1.P == 0) continue;\n\n            auto acts2 = generate_actions(firsts[i].b1, A1, true);\n\n            struct C2 {\n                MacroAction act2;\n                vector<string> b2;\n                int g2, quick2, guar2;\n                uint64_t key;\n            };\n            vector<C2> seconds;\n            seconds.reserve(acts2.size());\n\n            for (const auto& a2 : acts2) {\n                if (firsts[i].g1 + a2.k > legalLimit) continue;\n                auto b2 = apply_macro(firsts[i].b1, a2.dir, a2.idx, a2.k);\n                Analysis A2 = analyze_board(b2);\n                if (!A2.allSafe) continue;\n                if (firsts[i].g1 + a2.k + A2.guaranteedTail > legalLimit) continue;\n                seconds.push_back({a2, std::move(b2),\n                                   firsts[i].g1 + a2.k,\n                                   firsts[i].g1 + a2.k + min(A2.greedyTail, A2.guaranteedTail),\n                                   firsts[i].g1 + a2.k + A2.guaranteedTail,\n                                   rng.next()});\n            }\n\n            sort(seconds.begin(), seconds.end(), [&](const C2& a, const C2& b) {\n                if (a.quick2 != b.quick2) return a.quick2 < b.quick2;\n                if (a.guar2 != b.guar2) return a.guar2 < b.guar2;\n                if ((a.act2.removed == 0) != (b.act2.removed == 0)) return a.act2.removed > b.act2.removed;\n                long long lhs = 1LL * a.act2.removed * b.act2.k;\n                long long rhs = 1LL * b.act2.removed * a.act2.k;\n                if (lhs != rhs) return lhs > rhs;\n                if (a.act2.k != b.act2.k) return a.act2.k < b.act2.k;\n                return a.key < b.key;\n            });\n\n            if ((int)seconds.size() > 6) seconds.resize(6);\n\n            for (int j = 0; j < (int)seconds.size(); j++) {\n                if (chrono::steady_clock::now() >= deadline) break;\n                MemoVal tail2 = solve_tail_memoized(seconds[j].b2, tailMemo);\n                if (tail2.cost >= INF) continue;\n                int total2 = seconds[j].g2 + tail2.cost;\n                if (total2 < bestTotal) {\n                    bestTotal = total2;\n                    chosenI = i;\n                    chosenJ = j;\n                    chosenTail = tail2;\n                    chosenBoard = seconds[j].b2;\n                    chosenA1 = firsts[i].act1;\n                    chosenA2 = seconds[j].act2;\n                    chosenG = seconds[j].g2;\n                }\n            }\n        }\n\n        if (chosenI == -1) break;\n\n        for (int t = 0; t < chosenA1.k; t++) best.ops.push_back({chosenA1.dir, chosenA1.idx});\n        if (chosenJ != -1) {\n            for (int t = 0; t < chosenA2.k; t++) best.ops.push_back({chosenA2.dir, chosenA2.idx});\n        }\n        best.board = std::move(chosenBoard);\n        best.g = chosenG;\n        best.total = bestTotal;\n        best.tail = chosenTail;\n        best.h = hash_board(best.board);\n    }\n}\n\nstatic void exact_local_descent(\n    State& best,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    XorShift& rng,\n    chrono::steady_clock::time_point deadline,\n    int legalLimit\n) {\n    while (chrono::steady_clock::now() < deadline) {\n        Analysis A = analyze_board(best.board);\n        if (!A.allSafe || A.P == 0) break;\n\n        auto acts = generate_actions(best.board, A, true);\n        if (acts.empty()) break;\n\n        struct Q {\n            MacroAction act;\n            vector<string> board;\n            int quick, guaranteed, g2;\n            uint64_t key;\n        };\n        vector<Q> qs;\n        qs.reserve(acts.size());\n\n        for (const auto& act : acts) {\n            if (best.g + act.k > legalLimit) continue;\n            auto nb = apply_macro(best.board, act.dir, act.idx, act.k);\n            Analysis na = analyze_board(nb);\n            if (!na.allSafe) continue;\n            if (best.g + act.k + na.guaranteedTail > legalLimit) continue;\n            qs.push_back({act, std::move(nb),\n                          best.g + act.k + min(na.greedyTail, na.guaranteedTail),\n                          best.g + act.k + na.guaranteedTail,\n                          best.g + act.k,\n                          rng.next()});\n        }\n\n        if (qs.empty()) break;\n\n        sort(qs.begin(), qs.end(), [&](const Q& a, const Q& b) {\n            if (a.quick != b.quick) return a.quick < b.quick;\n            if (a.guaranteed != b.guaranteed) return a.guaranteed < b.guaranteed;\n            if ((a.act.removed == 0) != (b.act.removed == 0)) return a.act.removed > b.act.removed;\n            long long lhs = 1LL * a.act.removed * b.act.k;\n            long long rhs = 1LL * b.act.removed * a.act.k;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.act.k != b.act.k) return a.act.k < b.act.k;\n            return a.key < b.key;\n        });\n\n        if ((int)qs.size() > 14) qs.resize(14);\n\n        int bestIdx = -1;\n        int bestTotal = best.total;\n        MemoVal bestTail;\n\n        for (int i = 0; i < (int)qs.size(); i++) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            MemoVal tail = solve_tail_memoized(qs[i].board, tailMemo);\n            if (tail.cost >= INF) continue;\n            int total = qs[i].g2 + tail.cost;\n            if (total < bestTotal) {\n                bestTotal = total;\n                bestIdx = i;\n                bestTail = tail;\n            }\n        }\n\n        if (bestIdx == -1) break;\n\n        for (int t = 0; t < qs[bestIdx].act.k; t++) {\n            best.ops.push_back({qs[bestIdx].act.dir, qs[bestIdx].act.idx});\n        }\n        best.board = std::move(qs[bestIdx].board);\n        best.g = qs[bestIdx].g2;\n        best.total = bestTotal;\n        best.tail = bestTail;\n        best.h = hash_board(best.board);\n    }\n}\n\n// ---------- Prefix replay / simplification ----------\n\nstatic char removed_char_before_op(const vector<string>& B, pair<char,int> op) {\n    char d = op.first;\n    int p = op.second;\n    int N = (int)B.size();\n    if (d == 'L') return B[p][0];\n    if (d == 'R') return B[p][N - 1];\n    if (d == 'U') return B[0][p];\n    return B[N - 1][p];\n}\n\nstatic bool replay_ops_skip_safe(\n    const vector<string>& orig,\n    const vector<pair<char,int>>& ops,\n    int skipIndex,\n    vector<string>& outBoard,\n    vector<char>* removeds = nullptr\n) {\n    vector<string> B = orig;\n    if (removeds) {\n        removeds->clear();\n        removeds->reserve(ops.size());\n    }\n    for (int i = 0; i < (int)ops.size(); i++) {\n        char rc = removed_char_before_op(B, ops[i]);\n        if (removeds) removeds->push_back(rc);\n        if (i == skipIndex) continue;\n        if (rc == 'o') return false;\n        B = apply_macro(B, ops[i].first, ops[i].second, 1);\n    }\n    outBoard = std::move(B);\n    return true;\n}\n\nstatic bool replay_prefix_safe(\n    const vector<string>& orig,\n    const vector<pair<char,int>>& ops,\n    int prefixLen,\n    vector<string>& outBoard\n) {\n    vector<string> B = orig;\n    for (int i = 0; i < prefixLen; i++) {\n        char rc = removed_char_before_op(B, ops[i]);\n        if (rc == 'o') return false;\n        B = apply_macro(B, ops[i].first, ops[i].second, 1);\n    }\n    outBoard = std::move(B);\n    return true;\n}\n\nstatic void reverse_delete_prefix(\n    State& best,\n    const vector<string>& originalBoard,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    chrono::steady_clock::time_point deadline,\n    int legalLimit\n) {\n    bool improved = true;\n    while (improved && chrono::steady_clock::now() < deadline) {\n        improved = false;\n        if (best.ops.empty()) break;\n\n        vector<char> removeds;\n        vector<string> fullBoard;\n        if (!replay_ops_skip_safe(originalBoard, best.ops, -1, fullBoard, &removeds)) {\n            break;\n        }\n\n        vector<int> candIdx;\n        int M = (int)best.ops.size();\n\n        for (int i = M - 1; i >= 0; i--) {\n            if (removeds[i] == '.') candIdx.push_back(i);\n            if ((int)candIdx.size() >= 16) break;\n        }\n        for (int i = M - 1; i >= max(0, M - 20); i--) candIdx.push_back(i);\n\n        sort(candIdx.begin(), candIdx.end());\n        candIdx.erase(unique(candIdx.begin(), candIdx.end()), candIdx.end());\n        reverse(candIdx.begin(), candIdx.end());\n\n        for (int idx : candIdx) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            vector<string> nb;\n            if (!replay_ops_skip_safe(originalBoard, best.ops, idx, nb, nullptr)) continue;\n\n            MemoVal tail = solve_tail_memoized(nb, tailMemo);\n            if (tail.cost >= INF) continue;\n\n            int total = (int)best.ops.size() - 1 + tail.cost;\n            if (total <= legalLimit && total < best.total) {\n                best.ops.erase(best.ops.begin() + idx);\n                best.board = std::move(nb);\n                best.g = (int)best.ops.size();\n                best.total = total;\n                best.tail = tail;\n                best.h = hash_board(best.board);\n                improved = true;\n                break;\n            }\n        }\n    }\n}\n\nstatic void truncate_suffix_prefix(\n    State& best,\n    const vector<string>& originalBoard,\n    unordered_map<uint64_t, MemoVal>& tailMemo,\n    chrono::steady_clock::time_point deadline,\n    int legalLimit\n) {\n    bool improved = true;\n    while (improved && chrono::steady_clock::now() < deadline) {\n        improved = false;\n        int M = (int)best.ops.size();\n        if (M == 0) break;\n\n        vector<int> candLens;\n        for (int t = M - 1; t >= max(0, M - 24); --t) candLens.push_back(t);\n        for (int step = 2; step <= 5; ++step) {\n            int t = M - M / step;\n            if (0 <= t && t < M) candLens.push_back(t);\n        }\n        candLens.push_back(0);\n\n        sort(candLens.begin(), candLens.end());\n        candLens.erase(unique(candLens.begin(), candLens.end()), candLens.end());\n        reverse(candLens.begin(), candLens.end());\n\n        for (int t : candLens) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            vector<string> nb;\n            if (!replay_prefix_safe(originalBoard, best.ops, t, nb)) continue;\n\n            MemoVal tail = solve_tail_memoized(nb, tailMemo);\n            if (tail.cost >= INF) continue;\n\n            int total = t + tail.cost;\n            if (total <= legalLimit && total < best.total) {\n                best.ops.resize(t);\n                best.board = std::move(nb);\n                best.g = t;\n                best.total = total;\n                best.tail = tail;\n                best.h = hash_board(best.board);\n                improved = true;\n                break;\n            }\n        }\n    }\n}\n\n// ---------- Final validation ----------\n\nstatic pair<int,int> simulate_solution(\n    vector<string> B,\n    const vector<pair<char,int>>& ops\n) {\n    int N = (int)B.size();\n    int removedFuku = 0;\n\n    auto apply1 = [&](char d, int p) {\n        if (d == 'L') {\n            if (B[p][0] == 'o') removedFuku++;\n            string t(N, '.');\n            for (int j = 1; j < N; j++) t[j - 1] = B[p][j];\n            B[p] = t;\n        } else if (d == 'R') {\n            if (B[p][N - 1] == 'o') removedFuku++;\n            string t(N, '.');\n            for (int j = 0; j + 1 < N; j++) t[j + 1] = B[p][j];\n            B[p] = t;\n        } else if (d == 'U') {\n            if (B[0][p] == 'o') removedFuku++;\n            for (int i = 1; i < N; i++) B[i - 1][p] = B[i][p];\n            B[N - 1][p] = '.';\n        } else {\n            if (B[N - 1][p] == 'o') removedFuku++;\n            for (int i = N - 2; i >= 0; i--) B[i + 1][p] = B[i][p];\n            B[0][p] = '.';\n        }\n    };\n\n    for (auto [d, p] : ops) apply1(d, p);\n\n    int remainOni = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (B[i][j] == 'x') remainOni++;\n    return {remainOni, removedFuku};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_zob();\n\n    int N;\n    cin >> N;\n    vector<string> originalBoard(N);\n    for (int i = 0; i < N; i++) cin >> originalBoard[i];\n\n    const int LEGAL_LIMIT = 4 * N * N;\n\n    auto start = chrono::steady_clock::now();\n    auto deadline = start + chrono::milliseconds(1850);\n    auto searchEnd = deadline - chrono::milliseconds(150);\n\n    uint64_t seed = 0;\n    for (auto& row : originalBoard) for (char ch : row) seed = seed * 131 + ch;\n    XorShift rng(seed ^ 0x123456789abcdefULL);\n\n    unordered_map<uint64_t, MemoVal> tailMemo;\n    tailMemo.reserve(4096);\n\n    MemoVal baseTail = solve_tail_memoized(originalBoard, tailMemo);\n\n    State init;\n    init.board = originalBoard;\n    init.ops.clear();\n    init.g = 0;\n    init.total = baseTail.cost;\n    init.tail = baseTail;\n    init.h = hash_board(originalBoard);\n\n    State best = init;\n\n    vector<int> weights = {5, 3, 2, 1, 1};\n    int R = (int)weights.size();\n\n    for (int r = 0; r < R; r++) {\n        auto now = chrono::steady_clock::now();\n        if (now >= searchEnd) break;\n\n        long long remainingMs = chrono::duration_cast<chrono::milliseconds>(searchEnd - now).count();\n        int remainingWeight = 0;\n        for (int i = r; i < R; i++) remainingWeight += weights[i];\n        long long sliceMs = max<long long>(30, remainingMs * weights[r] / max(1, remainingWeight));\n        auto localDeadline = min(searchEnd, now + chrono::milliseconds(sliceMs));\n\n        bool randomized = (r > 0);\n        State cand = beam_search_restart(init, tailMemo, rng, localDeadline, randomized, LEGAL_LIMIT);\n        if (cand.total < best.total || (cand.total == best.total && cand.g < best.g)) {\n            best = std::move(cand);\n        }\n    }\n\n    if (chrono::steady_clock::now() < deadline - chrono::milliseconds(70)) {\n        State cand = beam_search_restart(best, tailMemo, rng, deadline - chrono::milliseconds(70), true, LEGAL_LIMIT);\n        if (cand.total < best.total || (cand.total == best.total && cand.g < best.g)) {\n            best = std::move(cand);\n        }\n    }\n\n    if (chrono::steady_clock::now() < deadline - chrono::milliseconds(32)) {\n        exact_two_step_descent(best, tailMemo, rng, deadline - chrono::milliseconds(32), LEGAL_LIMIT);\n    }\n\n    if (chrono::steady_clock::now() < deadline - chrono::milliseconds(16)) {\n        exact_local_descent(best, tailMemo, rng, deadline - chrono::milliseconds(16), LEGAL_LIMIT);\n    }\n\n    State backupBeforeCleanup = best;\n\n    if (chrono::steady_clock::now() < deadline - chrono::milliseconds(8)) {\n        reverse_delete_prefix(best, originalBoard, tailMemo, deadline - chrono::milliseconds(8), LEGAL_LIMIT);\n    }\n\n    if (chrono::steady_clock::now() < deadline - chrono::milliseconds(3)) {\n        truncate_suffix_prefix(best, originalBoard, tailMemo, deadline - chrono::milliseconds(3), LEGAL_LIMIT);\n    }\n\n    auto build_tail_ops = [&](const State& st) {\n        vector<int> tailDepth(4 * N, 0);\n        for (int f = 0; f < 4 * N; f++) tailDepth[f] = st.tail.depth[f];\n        return depth_to_ops(tailDepth, N);\n    };\n\n    auto tailOps = build_tail_ops(best);\n    vector<pair<char,int>> finalOps = best.ops;\n    finalOps.insert(finalOps.end(), tailOps.begin(), tailOps.end());\n\n    auto [remainOni, removedFuku] = simulate_solution(originalBoard, finalOps);\n\n    if ((int)finalOps.size() > LEGAL_LIMIT || remainOni != 0 || removedFuku != 0) {\n        best = backupBeforeCleanup;\n        tailOps = build_tail_ops(best);\n        finalOps = best.ops;\n        finalOps.insert(finalOps.end(), tailOps.begin(), tailOps.end());\n        tie(remainOni, removedFuku) = simulate_solution(originalBoard, finalOps);\n    }\n\n    if ((int)finalOps.size() > LEGAL_LIMIT || remainOni != 0 || removedFuku != 0) {\n        Analysis A = analyze_board(originalBoard);\n        vector<int> fb = build_individual_fallback_depth(A);\n        finalOps = depth_to_ops(fb, N);\n    }\n\n    for (auto [c, p] : finalOps) {\n        cout << c << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\n#include <atcoder/scc>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic inline long long AbsLL(long long x) { return x >= 0 ? x : -x; }\n\nstruct State {\n    vector<int> a, b;\n    vector<int> cnt;\n    vector<int> useA, useB;\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstruct Solver {\n    int N, L;\n    vector<int> T;\n    vector<int> D; // target incoming counts: D[0]=T[0]-1, D[i]=T[i] for i>0\n    mt19937_64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver(int N_, int L_, vector<int> T_)\n        : N(N_), L(L_), T(std::move(T_)),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        st = chrono::steady_clock::now();\n        D = T;\n        D[0]--;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    State simulate(const vector<int>& a, const vector<int>& b) {\n        State res;\n        res.a = a;\n        res.b = b;\n        res.cnt.assign(N, 0);\n        res.useA.assign(N, 0);\n        res.useB.assign(N, 0);\n\n        int x = 0;\n        res.cnt[0] = 1;\n        for (int step = 1; step < L; step++) {\n            if (res.cnt[x] & 1) {\n                res.useA[x]++;\n                x = a[x];\n            } else {\n                res.useB[x]++;\n                x = b[x];\n            }\n            res.cnt[x]++;\n        }\n        res.last = x;\n\n        long long e = 0;\n        for (int i = 0; i < N; i++) e += AbsLL((long long)res.cnt[i] - T[i]);\n        res.err = e;\n        return res;\n    }\n\n    vector<vector<int>> get_sccs(const vector<int>& a, const vector<int>& b) {\n        scc_graph g(N);\n        for (int i = 0; i < N; i++) {\n            g.add_edge(i, a[i]);\n            g.add_edge(i, b[i]);\n        }\n        return g.scc();\n    }\n\n    void repair_components(vector<int>& a, vector<int>& b,\n                           const vector<int>& wA, const vector<int>& wB,\n                           vector<long long>& R) {\n        for (int iter = 0; iter < 4; iter++) {\n            auto comps = get_sccs(a, b);\n            if ((int)comps.size() <= 1) return;\n\n            int K = (int)comps.size();\n            vector<int> cid(N, -1);\n            for (int i = 0; i < K; i++) {\n                for (int v : comps[i]) cid[v] = i;\n            }\n\n            vector<int> rep(K);\n            for (int i = 0; i < K; i++) {\n                int best = comps[i][0];\n                for (int v : comps[i]) {\n                    if (T[v] < T[best]) best = v;\n                }\n                rep[i] = best;\n            }\n\n            for (int i = 0; i < K; i++) {\n                int target = rep[(i + 1) % K];\n\n                long long bestKey = (1LL << 62);\n                int bestu = -1, bestslot = -1, bestold = -1, bestw = 0;\n\n                for (int u : comps[i]) {\n                    for (int slot = 0; slot < 2; slot++) {\n                        int old = (slot == 0 ? a[u] : b[u]);\n                        int w = (slot == 0 ? wA[u] : wB[u]);\n\n                        if (old == target) {\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                            bestKey = LLONG_MIN;\n                            break;\n                        }\n\n                        long long delta =\n                            AbsLL(R[old] + w) + AbsLL(R[target] - w)\n                            - AbsLL(R[old]) - AbsLL(R[target]);\n\n                        long long key = delta * 1000000LL + w;\n                        int other = (slot == 0 ? b[u] : a[u]);\n                        if (cid[other] == i) key -= 1;\n\n                        if (key < bestKey) {\n                            bestKey = key;\n                            bestu = u;\n                            bestslot = slot;\n                            bestold = old;\n                            bestw = w;\n                        }\n                    }\n                    if (bestKey == LLONG_MIN) break;\n                }\n\n                if (bestu != -1 && bestold != target) {\n                    R[bestold] += bestw;\n                    R[target] -= bestw;\n                    if (bestslot == 0) a[bestu] = target;\n                    else b[bestu] = target;\n                }\n            }\n        }\n    }\n\n    pair<vector<int>, vector<int>> initial_weights_assuming_last(int last) {\n        vector<int> wA(N), wB(N);\n        for (int i = 0; i < N; i++) {\n            int departures = T[i] - (i == last ? 1 : 0);\n            if (departures < 0) departures = 0;\n            wA[i] = (departures + 1) / 2;\n            wB[i] = departures / 2;\n        }\n        return {wA, wB};\n    }\n\n    pair<vector<int>, vector<int>> hybrid_weights(const State& cur, int last, int p, int q) {\n        auto [iA, iB] = initial_weights_assuming_last(last);\n        vector<int> wA(N), wB(N);\n\n        struct Rem {\n            int r, idx;\n        };\n        vector<Rem> rems;\n        rems.reserve(2 * N);\n\n        int den = p + q;\n        long long sum = 0;\n        for (int i = 0; i < N; i++) {\n            int vals[2] = {\n                p * cur.useA[i] + q * iA[i],\n                p * cur.useB[i] + q * iB[i]\n            };\n            for (int k = 0; k < 2; k++) {\n                int base = vals[k] / den;\n                int rem = vals[k] % den;\n                if (k == 0) wA[i] = base;\n                else wB[i] = base;\n                sum += base;\n                rems.push_back({rem, 2 * i + k});\n            }\n        }\n\n        long long need = (L - 1) - sum;\n        shuffle(rems.begin(), rems.end(), rng);\n        stable_sort(rems.begin(), rems.end(), [&](const Rem& x, const Rem& y) {\n            return x.r > y.r;\n        });\n        for (int t = 0; t < need && t < (int)rems.size(); t++) {\n            int idx = rems[t].idx;\n            if ((idx & 1) == 0) wA[idx / 2]++;\n            else wB[idx / 2]++;\n        }\n\n        return {wA, wB};\n    }\n\n    void optimize_assignment(vector<int>& dest, const vector<int>& W, vector<long long>& R) {\n        const int M = 2 * N;\n\n        for (int iter = 0; iter < 800; iter++) {\n            long long bestDelta = 0;\n            int bestType = -1; // 0: move, 1: swap\n            int bp = -1, bq = -1, bv = -1;\n\n            for (int p = 0; p < M; p++) {\n                int w = W[p];\n                if (w == 0) continue;\n                int u = dest[p];\n                for (int v = 0; v < N; v++) if (v != u) {\n                    long long delta =\n                        AbsLL(R[u] + w) + AbsLL(R[v] - w)\n                        - AbsLL(R[u]) - AbsLL(R[v]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 0;\n                        bp = p;\n                        bv = v;\n                    }\n                }\n            }\n\n            for (int p = 0; p < M; p++) {\n                int wp = W[p];\n                int u = dest[p];\n                for (int q = p + 1; q < M; q++) {\n                    int wq = W[q];\n                    int v = dest[q];\n                    if (u == v) continue;\n                    if (wp == wq) continue;\n                    long long delta =\n                        AbsLL(R[u] + wp - wq) + AbsLL(R[v] + wq - wp)\n                        - AbsLL(R[u]) - AbsLL(R[v]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n\n            if (bestType == 0) {\n                int p = bp;\n                int w = W[p];\n                int u = dest[p];\n                int v = bv;\n                R[u] += w;\n                R[v] -= w;\n                dest[p] = v;\n            } else if (bestType == 1) {\n                int p = bp, q = bq;\n                int wp = W[p], wq = W[q];\n                int u = dest[p], v = dest[q];\n                R[u] += wp - wq;\n                R[v] += wq - wp;\n                swap(dest[p], dest[q]);\n            } else {\n                break;\n            }\n        }\n    }\n\n    State build_from_weights(const vector<int>& wA, const vector<int>& wB,\n                             const vector<int>* baseA = nullptr,\n                             const vector<int>* baseB = nullptr,\n                             int mode = 0) {\n        vector<long long> R(N);\n        for (int i = 0; i < N; i++) R[i] = D[i];\n\n        vector<int> W(2 * N), dest(2 * N, -1);\n        for (int i = 0; i < N; i++) {\n            W[2 * i] = wA[i];\n            W[2 * i + 1] = wB[i];\n        }\n\n        vector<int> ids(2 * N);\n        iota(ids.begin(), ids.end(), 0);\n        shuffle(ids.begin(), ids.end(), rng);\n        stable_sort(ids.begin(), ids.end(), [&](int p, int q) {\n            if (W[p] != W[q]) return W[p] > W[q];\n            return p < q;\n        });\n\n        long long same_pen = (mode % 4 == 0 ? 20 : mode % 4 == 1 ? 80 : mode % 4 == 2 ? 200 : 500);\n        long long self_pen = (mode % 5 == 0 ? 10 : mode % 5 == 1 ? 80 : mode % 5 == 2 ? 200 : mode % 5 == 3 ? 500 : 1200);\n        long long keep_bonus = (baseA && baseB) ? (mode % 3 == 0 ? 30 : mode % 3 == 1 ? 100 : 250) : 0;\n\n        vector<int> first_dest(N, -1);\n\n        for (int pid : ids) {\n            int owner = pid / 2;\n            int w = W[pid];\n\n            vector<pair<long long, int>> cand;\n            cand.reserve(N);\n            for (int j = 0; j < N; j++) {\n                long long delta = AbsLL(R[j] - w) - AbsLL(R[j]);\n                long long sc = delta * 1000;\n                if (first_dest[owner] == j) sc += same_pen;\n                if (j == owner) sc += self_pen;\n                if (baseA && baseB) {\n                    int bd = (pid % 2 == 0 ? (*baseA)[owner] : (*baseB)[owner]);\n                    if (bd == j) sc -= keep_bonus;\n                }\n                sc += (long long)(rng() % 23);\n                cand.push_back({sc, j});\n            }\n\n            int pickK = min(6, N);\n            nth_element(cand.begin(), cand.begin() + (pickK - 1), cand.end());\n            sort(cand.begin(), cand.begin() + pickK);\n\n            int choose = (int)(rng() % pickK);\n            int j = cand[choose].second;\n            dest[pid] = j;\n            if (first_dest[owner] == -1) first_dest[owner] = j;\n            R[j] -= w;\n        }\n\n        optimize_assignment(dest, W, R);\n\n        vector<int> a(N), b(N);\n        for (int i = 0; i < N; i++) {\n            a[i] = dest[2 * i];\n            b[i] = dest[2 * i + 1];\n        }\n\n        repair_components(a, b, wA, wB, R);\n        return simulate(a, b);\n    }\n\n    State build_target_based(int last, const State* base, int mode) {\n        auto [wA, wB] = initial_weights_assuming_last(last);\n        if (base) return build_from_weights(wA, wB, &base->a, &base->b, mode);\n        return build_from_weights(wA, wB, nullptr, nullptr, mode);\n    }\n\n    State build_hybrid_based(const State& cur, int last, int p, int q, int mode) {\n        auto [wA, wB] = hybrid_weights(cur, last, p, q);\n        return build_from_weights(wA, wB, &cur.a, &cur.b, mode);\n    }\n\n    State rebuild_from_state(const State& cur, int mode) {\n        return build_from_weights(cur.useA, cur.useB, &cur.a, &cur.b, mode);\n    }\n\n    struct MoveCand {\n        int type; // 0 redirect, 1 swap_ab, 2 swap_slots\n        long long approx;\n        int n1, s1, to;\n        int n2, s2;\n    };\n\n    State guided_local_improve(State cur, double time_limit) {\n        while (elapsed() < time_limit) {\n            vector<long long> diff(N);\n            for (int i = 0; i < N; i++) diff[i] = (long long)cur.cnt[i] - T[i];\n\n            vector<int> under, over;\n            for (int i = 0; i < N; i++) {\n                if (diff[i] < 0) under.push_back(i);\n                if (diff[i] > 0) over.push_back(i);\n            }\n            sort(under.begin(), under.end(), [&](int x, int y) { return diff[x] < diff[y]; });\n            sort(over.begin(), over.end(), [&](int x, int y) { return diff[x] > diff[y]; });\n\n            vector<int> topUnder(min<int>(12, under.size()));\n            vector<int> topOver(min<int>(12, over.size()));\n            for (int i = 0; i < (int)topUnder.size(); i++) topUnder[i] = under[i];\n            for (int i = 0; i < (int)topOver.size(); i++) topOver[i] = over[i];\n\n            vector<char> isTopUnder(N, 0), isTopOver(N, 0);\n            for (int v : topUnder) isTopUnder[v] = 1;\n            for (int v : topOver) isTopOver[v] = 1;\n\n            struct SlotInfo {\n                int node, slot, w, dest;\n            };\n            vector<SlotInfo> slots;\n            slots.reserve(2 * N);\n            for (int i = 0; i < N; i++) {\n                if (cur.useA[i] > 0) slots.push_back({i, 0, cur.useA[i], cur.a[i]});\n                if (cur.useB[i] > 0) slots.push_back({i, 1, cur.useB[i], cur.b[i]});\n            }\n\n            vector<MoveCand> cands;\n            cands.reserve(6000);\n\n            for (auto &sl : slots) {\n                int w = sl.w;\n                int u = sl.dest;\n                int lim = min<int>(14, under.size());\n                for (int k = 0; k < lim; k++) {\n                    int v = under[k];\n                    if (v == u) continue;\n                    long long approx =\n                        AbsLL(diff[u] - w) + AbsLL(diff[v] + w)\n                        - AbsLL(diff[u]) - AbsLL(diff[v]);\n                    if (approx <= 0) {\n                        cands.push_back({0, approx, sl.node, sl.slot, v, -1, -1});\n                    }\n                }\n            }\n\n            for (int i = 0; i < N; i++) {\n                if (cur.a[i] != cur.b[i]) {\n                    cands.push_back({1, 0, i, 0, 0, -1, -1});\n                }\n            }\n\n            vector<int> overSlotIds, underSlotIds;\n            for (int idx = 0; idx < (int)slots.size(); idx++) {\n                if (isTopOver[slots[idx].dest]) overSlotIds.push_back(idx);\n                if (isTopUnder[slots[idx].dest]) underSlotIds.push_back(idx);\n            }\n\n            auto cmpSlot = [&](int x, int y) {\n                if (slots[x].w != slots[y].w) return slots[x].w > slots[y].w;\n                return x < y;\n            };\n            sort(overSlotIds.begin(), overSlotIds.end(), cmpSlot);\n            sort(underSlotIds.begin(), underSlotIds.end(), cmpSlot);\n            if ((int)overSlotIds.size() > 28) overSlotIds.resize(28);\n            if ((int)underSlotIds.size() > 28) underSlotIds.resize(28);\n\n            for (int ix : overSlotIds) {\n                for (int iy : underSlotIds) {\n                    if (ix == iy) continue;\n                    const auto &p = slots[ix];\n                    const auto &q = slots[iy];\n                    if (p.dest == q.dest) continue;\n                    if (p.w == q.w) continue;\n\n                    int u = p.dest, v = q.dest;\n                    long long approx =\n                        AbsLL(diff[u] - p.w + q.w) + AbsLL(diff[v] - q.w + p.w)\n                        - AbsLL(diff[u]) - AbsLL(diff[v]);\n\n                    if (approx <= 0) {\n                        cands.push_back({2, approx, p.node, p.slot, 0, q.node, q.slot});\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            shuffle(cands.begin(), cands.end(), rng);\n            stable_sort(cands.begin(), cands.end(), [&](const MoveCand& x, const MoveCand& y) {\n                return x.approx < y.approx;\n            });\n\n            int evals = min<int>(18, cands.size());\n            State bestNext = cur;\n            bool improved = false;\n\n            for (int idx = 0; idx < evals && elapsed() < time_limit; idx++) {\n                const auto& cd = cands[idx];\n                vector<int> na = cur.a, nb = cur.b;\n\n                if (cd.type == 0) {\n                    if (cd.s1 == 0) {\n                        if (na[cd.n1] == cd.to) continue;\n                        na[cd.n1] = cd.to;\n                    } else {\n                        if (nb[cd.n1] == cd.to) continue;\n                        nb[cd.n1] = cd.to;\n                    }\n                } else if (cd.type == 1) {\n                    swap(na[cd.n1], nb[cd.n1]);\n                } else {\n                    int d1 = (cd.s1 == 0 ? na[cd.n1] : nb[cd.n1]);\n                    int d2 = (cd.s2 == 0 ? na[cd.n2] : nb[cd.n2]);\n                    if (d1 == d2) continue;\n                    if (cd.s1 == 0) na[cd.n1] = d2;\n                    else nb[cd.n1] = d2;\n                    if (cd.s2 == 0) na[cd.n2] = d1;\n                    else nb[cd.n2] = d1;\n                }\n\n                State nxt = simulate(na, nb);\n                if (nxt.err < bestNext.err) {\n                    bestNext = std::move(nxt);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            cur = std::move(bestNext);\n        }\n        return cur;\n    }\n\n    State solve() {\n        State best;\n        best.err = (1LL << 60);\n\n        vector<int> pos;\n        for (int i = 0; i < N; i++) if (T[i] > 0) pos.push_back(i);\n        sort(pos.begin(), pos.end(), [&](int x, int y) {\n            if (T[x] != T[y]) return T[x] > T[y];\n            return x < y;\n        });\n        if (pos.empty()) pos.push_back(0);\n\n        int mode = 0;\n        int ptr = 0;\n\n        // Initial exploration\n        while (elapsed() < 0.34) {\n            int last;\n            if (ptr < min<int>(14, pos.size())) last = pos[ptr];\n            else last = pos[(int)(rng() % pos.size())];\n            State cand = build_target_based(last, nullptr, mode++);\n            if (cand.err < best.err) best = std::move(cand);\n            ptr++;\n        }\n\n        // Main search\n        int stagnation = 0;\n        while (elapsed() < 1.76) {\n            State cand;\n            int typ = mode % 6;\n\n            if (typ == 0) {\n                cand = rebuild_from_state(best, mode++);\n            } else if (typ == 1) {\n                cand = build_target_based(best.last, &best, mode++);\n            } else if (typ == 2) {\n                int last = pos[(int)(rng() % min<int>(14, pos.size()))];\n                cand = build_target_based(last, &best, mode++);\n            } else if (typ == 3) {\n                int last = pos[(int)(rng() % pos.size())];\n                cand = build_target_based(last, nullptr, mode++);\n            } else if (typ == 4) {\n                cand = build_hybrid_based(best, best.last, 2, 1, mode++);\n            } else {\n                int last = pos[(int)(rng() % min<int>(14, pos.size()))];\n                cand = build_hybrid_based(best, last, 1, 1, mode++);\n            }\n\n            if (cand.err <= best.err + 1200 && elapsed() < 1.90) {\n                double lim = min(1.91, elapsed() + 0.030);\n                cand = guided_local_improve(std::move(cand), lim);\n            }\n\n            if (cand.err < best.err) {\n                best = std::move(cand);\n                stagnation = 0;\n            } else {\n                stagnation++;\n            }\n\n            if (stagnation >= 4 && elapsed() < 1.90) {\n                State alt = guided_local_improve(best, min(1.92, elapsed() + 0.020));\n                if (alt.err < best.err) {\n                    best = std::move(alt);\n                }\n                stagnation = 0;\n            }\n        }\n\n        // Final intensification\n        while (elapsed() < 1.965) {\n            State cand;\n            int typ = mode % 3;\n            if (typ == 0) {\n                cand = rebuild_from_state(best, mode++);\n            } else if (typ == 1) {\n                cand = build_target_based(best.last, &best, mode++);\n            } else {\n                cand = build_hybrid_based(best, best.last, 2, 1, mode++);\n            }\n\n            cand = guided_local_improve(std::move(cand), min(1.978, elapsed() + 0.018));\n            if (cand.err < best.err) best = std::move(cand);\n            else mode++;\n        }\n\n        best = guided_local_improve(std::move(best), 1.985);\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    vector<int> T(N);\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    Solver solver(N, L, T);\n    State ans = solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << ans.a[i] << ' ' << ans.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) x = p[x] = p[p[x]];\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a);\n        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\nstruct Solver {\n    static constexpr double INF = 1e100;\n    static constexpr double PI = 3.1415926535897932384626433832795;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<double> cx, cy;\n    vector<vector<double>> distm;\n    vector<uint32_t> morton_code, hilbert_code;\n    int used_queries = 0;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffff;\n        x = (x ^ (x << 8)) & 0x00FF00FF;\n        x = (x ^ (x << 4)) & 0x0F0F0F0F;\n        x = (x ^ (x << 2)) & 0x33333333;\n        x = (x ^ (x << 1)) & 0x55555555;\n        return x;\n    }\n\n    static void rot_hilbert(int n, int &x, int &y, int rx, int ry) {\n        if (ry == 0) {\n            if (rx == 1) {\n                x = n - 1 - x;\n                y = n - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    static uint32_t hilbert_xy2d(int bits, int x, int y) {\n        int n = 1 << bits;\n        uint32_t d = 0;\n        for (int s = n >> 1; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (uint32_t)(s * s) * (uint32_t)((3 * rx) ^ ry);\n            rot_hilbert(s, x, y, rx, ry);\n        }\n        return d;\n    }\n\n    static pair<int,int> norm_edge(int a, int b) {\n        if (a > b) swap(a, b);\n        return {a, b};\n    }\n\n    static uint64_t edge_key(int a, int b) {\n        if (a > b) swap(a, b);\n        return (uint64_t(uint32_t(a)) << 32) | uint32_t(b);\n    }\n\n    static uint64_t hash_vec_ordered(const vector<int>& v) {\n        uint64_t h = 1469598103934665603ULL;\n        for (int x : v) {\n            h ^= uint64_t(x + 1);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    vector<int> reversed_copy(const vector<int>& v) {\n        vector<int> r = v;\n        reverse(r.begin(), r.end());\n        return r;\n    }\n\n    void input() {\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        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx.resize(N); cy.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n        }\n\n        distm.assign(N, vector<double>(N, 0.0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                double dx = cx[i] - cx[j];\n                double dy = cy[i] - cy[j];\n                double d = sqrt(dx * dx + dy * dy);\n                distm[i][j] = distm[j][i] = d;\n            }\n        }\n\n        morton_code.resize(N);\n        hilbert_code.resize(N);\n        for (int i = 0; i < N; i++) {\n            int xi = int(round(cx[i]));\n            int yi = int(round(cy[i]));\n            xi = max(0, min(16383, xi));\n            yi = max(0, min(16383, yi));\n            morton_code[i] = part1by1((uint32_t)xi) | (part1by1((uint32_t)yi) << 1);\n            hilbert_code[i] = hilbert_xy2d(14, xi, yi);\n        }\n    }\n\n    vector<int> make_morton_order() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (morton_code[a] != morton_code[b]) return morton_code[a] < morton_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_hilbert_order() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (hilbert_code[a] != hilbert_code[b]) return hilbert_code[a] < hilbert_code[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> make_projection_order(double theta) {\n        double ct = cos(theta), st = sin(theta);\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double ka = cx[a] * ct + cy[a] * st;\n            double kb = cx[b] * ct + cy[b] * st;\n            if (fabs(ka - kb) > 1e-9) return ka < kb;\n            double ta = -cx[a] * st + cy[a] * ct;\n            double tb = -cx[b] * st + cy[b] * ct;\n            if (fabs(ta - tb) > 1e-9) return ta < tb;\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<int> order_group_by_key(const vector<int>& group, int mode) {\n        vector<int> ord = group;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto key = [&](int v) -> pair<double,double> {\n                if (mode == 0) return {cx[v], cy[v]};\n                if (mode == 1) return {cy[v], cx[v]};\n                if (mode == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n                if (mode == 3) return {cx[v] - cy[v], cx[v] + cy[v]};\n                if (mode == 4) return {double(morton_code[v]), double(v)};\n                return {double(hilbert_code[v]), double(v)};\n            };\n            auto ka = key(a), kb = key(b);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n        return ord;\n    }\n\n    double mst_cost_of_list(const vector<int>& cities) {\n        int n = (int)cities.size();\n        if (n <= 1) return 0.0;\n        vector<double> md(n, INF);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n        double ret = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            ret += md[v];\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) md[i] = d;\n            }\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_small(const vector<int>& cities) {\n        int n = (int)cities.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<double> md(n, INF);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        md[0] = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back(norm_edge(cities[v], cities[par[v]]));\n            int cv = cities[v];\n            for (int i = 0; i < n; i++) if (!used[i]) {\n                double d = distm[cv][cities[i]];\n                if (d < md[i]) {\n                    md[i] = d;\n                    par[i] = v;\n                }\n            }\n        }\n        return edges;\n    }\n\n    vector<pair<int,int>> approx_mst_edges_full(const vector<int>& cities) {\n        return approx_mst_edges_small(cities);\n    }\n\n    vector<int> mst_preorder_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        auto edges = approx_mst_edges_full(group);\n        unordered_map<int, vector<int>> adj;\n        adj.reserve(n * 2);\n        for (auto [a, b] : edges) {\n            adj[a].push_back(b);\n            adj[b].push_back(a);\n        }\n\n        int root = group[0];\n        for (int v : group) {\n            if (cx[v] + cy[v] < cx[root] + cy[root]) root = v;\n        }\n\n        vector<int> ord;\n        ord.reserve(n);\n        unordered_set<int> vis;\n        vis.reserve(n * 2);\n\n        vector<pair<int,int>> st;\n        st.push_back({root, -1});\n        while (!st.empty()) {\n            auto [v, p] = st.back();\n            st.pop_back();\n            if (vis.count(v)) continue;\n            vis.insert(v);\n            ord.push_back(v);\n\n            auto neis = adj[v];\n            sort(neis.begin(), neis.end(), [&](int a, int b) {\n                double da = distm[v][a], db = distm[v][b];\n                if (fabs(da - db) > 1e-9) return da > db;\n                return a > b;\n            });\n            for (int to : neis) if (to != p && !vis.count(to)) {\n                st.push_back({to, v});\n            }\n        }\n        if ((int)ord.size() != n) return group;\n        return ord;\n    }\n\n    vector<int> nearest_neighbor_order(const vector<int>& group, int start_mode) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        int start = group[0];\n        if (start_mode == 0) {\n            for (int v : group) if (cx[v] + cy[v] < cx[start] + cy[start]) start = v;\n        } else {\n            double gx = 0.0, gy = 0.0;\n            for (int v : group) gx += cx[v], gy += cy[v];\n            gx /= n; gy /= n;\n            double bestd = -1.0;\n            for (int v : group) {\n                double dx = cx[v] - gx, dy = cy[v] - gy;\n                double d = dx * dx + dy * dy;\n                if (d > bestd) bestd = d, start = v;\n            }\n        }\n\n        unordered_set<int> rem(group.begin(), group.end());\n        rem.reserve(n * 2);\n        vector<int> ord;\n        ord.reserve(n);\n        int cur = start;\n        ord.push_back(cur);\n        rem.erase(cur);\n\n        while (!rem.empty()) {\n            int best = -1;\n            double bd = INF;\n            for (int v : rem) {\n                double d = distm[cur][v];\n                if (d < bd - 1e-9 || (fabs(d - bd) <= 1e-9 && (best == -1 || v < best))) {\n                    bd = d;\n                    best = v;\n                }\n            }\n            cur = best;\n            ord.push_back(cur);\n            rem.erase(cur);\n        }\n        return ord;\n    }\n\n    struct OrderEvaluator {\n        const vector<int>& ord;\n        const vector<vector<double>>& distm;\n        int N;\n        vector<vector<double>> cache;\n\n        OrderEvaluator(const vector<int>& ord_, const vector<vector<double>>& distm_)\n            : ord(ord_), distm(distm_), N((int)ord_.size()),\n              cache(N + 1, vector<double>(N + 1, -1.0)) {}\n\n        double seg_cost(int l, int len) {\n            if (len <= 1) return 0.0;\n            double &res = cache[l][len];\n            if (res >= -0.5) return res;\n\n            vector<double> md(len, 1e100);\n            vector<char> used(len, 0);\n            md[0] = 0.0;\n            double ret = 0.0;\n\n            for (int it = 0; it < len; it++) {\n                int v = -1;\n                for (int i = 0; i < len; i++) {\n                    if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n                }\n                used[v] = 1;\n                ret += md[v];\n                int cv = ord[l + v];\n                for (int i = 0; i < len; i++) if (!used[i]) {\n                    double d = distm[cv][ord[l + i]];\n                    if (d < md[i]) md[i] = d;\n                }\n            }\n            res = ret;\n            return res;\n        }\n\n        double total_cost(const vector<int>& sizes) {\n            int pos = 0;\n            double ret = 0.0;\n            for (int s : sizes) {\n                ret += seg_cost(pos, s);\n                pos += s;\n            }\n            return ret;\n        }\n\n        vector<int> improve(vector<int> sizes, int passes = 4) {\n            int m = (int)sizes.size();\n            for (int pass = 0; pass < passes; pass++) {\n                bool any = false;\n                int pos = 0;\n                for (int i = 0; i + 1 < m; i++) {\n                    int a = sizes[i], b = sizes[i + 1];\n                    double oldc = seg_cost(pos, a) + seg_cost(pos + a, b);\n                    double newc = seg_cost(pos, b) + seg_cost(pos + b, a);\n                    if (newc + 1e-9 < oldc) {\n                        swap(sizes[i], sizes[i + 1]);\n                        any = true;\n                    }\n                    pos += sizes[i];\n                }\n                if (!any) break;\n            }\n            return sizes;\n        }\n    };\n\n    struct Candidate {\n        vector<vector<int>> groups_seq;\n        double score = INF;\n    };\n\n    Candidate candidate_from_order(const vector<int>& ord, const vector<int>& size_seq) {\n        OrderEvaluator eval(ord, distm);\n        auto sizes = eval.improve(size_seq, 5);\n        double sc = eval.total_cost(sizes);\n\n        vector<vector<int>> groups;\n        int pos = 0;\n        for (int s : sizes) {\n            vector<int> grp;\n            grp.reserve(s);\n            for (int i = 0; i < s; i++) grp.push_back(ord[pos + i]);\n            pos += s;\n            groups.push_back(move(grp));\n        }\n        return {groups, sc};\n    }\n\n    vector<vector<int>> kd_partition_rec(vector<int> cities, vector<int> sizes, int mode, int depth) {\n        if ((int)sizes.size() == 1) return {cities};\n\n        int total = 0;\n        for (int x : sizes) total += x;\n\n        int pref = 0;\n        int split_k = 1;\n        int best_diff = total;\n        for (int k = 1; k < (int)sizes.size(); k++) {\n            pref += sizes[k - 1];\n            int diff = abs(total - 2 * pref);\n            if (diff < best_diff) {\n                best_diff = diff;\n                split_k = k;\n            }\n        }\n\n        int left_need = 0;\n        for (int i = 0; i < split_k; i++) left_need += sizes[i];\n\n        auto choose_mode_key = [&](int v, int chosen) -> pair<double,double> {\n            if (chosen == 0) return {cx[v], cy[v]};\n            if (chosen == 1) return {cy[v], cx[v]};\n            if (chosen == 2) return {cx[v] + cy[v], cx[v] - cy[v]};\n            return {cx[v] - cy[v], cx[v] + cy[v]};\n        };\n\n        int chosen = 0;\n        if (mode == 0) {\n            double minx = 1e18, maxx = -1e18, miny = 1e18, maxy = -1e18;\n            for (int v : cities) {\n                minx = min(minx, cx[v]);\n                maxx = max(maxx, cx[v]);\n                miny = min(miny, cy[v]);\n                maxy = max(maxy, cy[v]);\n            }\n            chosen = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        } else if (mode == 1) {\n            chosen = depth % 2;\n        } else {\n            double mina = 1e18, maxa = -1e18, minb = 1e18, maxb = -1e18;\n            for (int v : cities) {\n                double a = cx[v] + cy[v];\n                double b = cx[v] - cy[v];\n                mina = min(mina, a); maxa = max(maxa, a);\n                minb = min(minb, b); maxb = max(maxb, b);\n            }\n            chosen = ((maxa - mina) >= (maxb - minb)) ? 2 : 3;\n        }\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            auto ka = choose_mode_key(a, chosen);\n            auto kb = choose_mode_key(b, chosen);\n            if (fabs(ka.first - kb.first) > 1e-9) return ka.first < kb.first;\n            if (fabs(ka.second - kb.second) > 1e-9) return ka.second < kb.second;\n            return a < b;\n        });\n\n        vector<int> left_cities(cities.begin(), cities.begin() + left_need);\n        vector<int> right_cities(cities.begin() + left_need, cities.end());\n        vector<int> left_sizes(sizes.begin(), sizes.begin() + split_k);\n        vector<int> right_sizes(sizes.begin() + split_k, sizes.end());\n\n        auto gl = kd_partition_rec(left_cities, left_sizes, mode, depth + 1);\n        auto gr = kd_partition_rec(right_cities, right_sizes, mode, depth + 1);\n        gl.insert(gl.end(), gr.begin(), gr.end());\n        return gl;\n    }\n\n    Candidate candidate_from_kd(const vector<int>& size_seq, int mode) {\n        vector<int> cities(N);\n        iota(cities.begin(), cities.end(), 0);\n        auto groups = kd_partition_rec(cities, size_seq, mode, 0);\n        double sc = 0.0;\n        for (auto &g : groups) sc += mst_cost_of_list(g);\n        return {groups, sc};\n    }\n\n    vector<vector<int>> assign_to_original_indices(const vector<vector<int>>& groups_seq) {\n        unordered_map<int, vector<int>> mp;\n        mp.reserve(M * 2);\n        for (int i = 0; i < M; i++) mp[G[i]].push_back(i);\n        for (auto &kv : mp) reverse(kv.second.begin(), kv.second.end());\n\n        vector<vector<int>> ret(M);\n        for (auto &grp : groups_seq) {\n            int s = (int)grp.size();\n            int idx = mp[s].back();\n            mp[s].pop_back();\n            ret[idx] = grp;\n        }\n        return ret;\n    }\n\n    double sqdist_city_to_point(int v, double x, double y) {\n        double dx = cx[v] - x;\n        double dy = cy[v] - y;\n        return dx * dx + dy * dy;\n    }\n\n    void recompute_group_info(const vector<vector<int>>& groups, int gid,\n                              vector<double>& gcx, vector<double>& gcy, vector<double>& gcost) {\n        double sx = 0.0, sy = 0.0;\n        for (int v : groups[gid]) {\n            sx += cx[v];\n            sy += cy[v];\n        }\n        gcx[gid] = sx / groups[gid].size();\n        gcy[gid] = sy / groups[gid].size();\n        gcost[gid] = mst_cost_of_list(groups[gid]);\n    }\n\n    void local_swap_optimize(vector<vector<int>>& groups) {\n        vector<double> gcx(M), gcy(M), gcost(M);\n        for (int i = 0; i < M; i++) recompute_group_info(groups, i, gcx, gcy, gcost);\n\n        const int PASSES = 2;\n        const int K_NEI = 5;\n        const int K_CAND = 4;\n\n        for (int pass = 0; pass < PASSES; pass++) {\n            bool any = false;\n\n            vector<vector<int>> neigh(M);\n            for (int i = 0; i < M; i++) {\n                vector<pair<double,int>> ds;\n                ds.reserve(M - 1);\n                for (int j = 0; j < M; j++) if (i != j) {\n                    double dx = gcx[i] - gcx[j];\n                    double dy = gcy[i] - gcy[j];\n                    ds.push_back({dx * dx + dy * dy, j});\n                }\n                int k = min(K_NEI, (int)ds.size());\n                if (k == 0) continue;\n                if (k < (int)ds.size()) nth_element(ds.begin(), ds.begin() + k, ds.end());\n                sort(ds.begin(), ds.begin() + k);\n                for (int t = 0; t < k; t++) neigh[i].push_back(ds[t].second);\n            }\n\n            set<pair<int,int>> pairs;\n            for (int i = 0; i < M; i++) {\n                for (int j : neigh[i]) {\n                    if (i < j) pairs.insert({i, j});\n                    else pairs.insert({j, i});\n                }\n            }\n\n            for (auto [a, b] : pairs) {\n                auto pick_candidates = [&](int from, int to) {\n                    vector<pair<double,int>> cand;\n                    cand.reserve(groups[from].size());\n                    for (int idx = 0; idx < (int)groups[from].size(); idx++) {\n                        int v = groups[from][idx];\n                        double score = sqdist_city_to_point(v, gcx[to], gcy[to])\n                                     - sqdist_city_to_point(v, gcx[from], gcy[from]);\n                        cand.push_back({score, idx});\n                    }\n                    int k = min(K_CAND, (int)cand.size());\n                    if (k == 0) return vector<int>{};\n                    if (k < (int)cand.size()) nth_element(cand.begin(), cand.begin() + k, cand.end());\n                    sort(cand.begin(), cand.begin() + k);\n                    vector<int> ret;\n                    for (int i = 0; i < k; i++) ret.push_back(cand[i].second);\n                    return ret;\n                };\n\n                auto ca = pick_candidates(a, b);\n                auto cb = pick_candidates(b, a);\n\n                double old_cost = gcost[a] + gcost[b];\n                double best_new = old_cost;\n                int besta = -1, bestb = -1;\n\n                for (int ia : ca) {\n                    for (int ib : cb) {\n                        vector<int> ga = groups[a];\n                        vector<int> gb = groups[b];\n                        swap(ga[ia], gb[ib]);\n                        double nc = mst_cost_of_list(ga) + mst_cost_of_list(gb);\n                        if (nc + 1e-9 < best_new) {\n                            best_new = nc;\n                            besta = ia;\n                            bestb = ib;\n                        }\n                    }\n                }\n\n                if (besta != -1) {\n                    swap(groups[a][besta], groups[b][bestb]);\n                    recompute_group_info(groups, a, gcx, gcy, gcost);\n                    recompute_group_info(groups, b, gcx, gcy, gcost);\n                    any = true;\n                }\n            }\n\n            if (!any) break;\n        }\n    }\n\n    vector<vector<int>> build_groups() {\n        vector<Candidate> cands;\n\n        vector<int> ascG = G;\n        sort(ascG.begin(), ascG.end());\n        vector<int> descG = G;\n        sort(descG.rbegin(), descG.rend());\n        vector<vector<int>> size_seqs = {G, ascG, descG};\n\n        vector<vector<int>> orders_raw;\n        orders_raw.push_back(make_morton_order());\n        orders_raw.push_back(make_hilbert_order());\n        orders_raw.push_back(make_projection_order(0.0));\n        orders_raw.push_back(make_projection_order(PI / 2.0));\n        orders_raw.push_back(make_projection_order(PI / 4.0));\n        orders_raw.push_back(make_projection_order(-PI / 4.0));\n        orders_raw.push_back(make_projection_order(PI / 8.0));\n        orders_raw.push_back(make_projection_order(3.0 * PI / 8.0));\n\n        vector<vector<int>> orders;\n        unordered_set<uint64_t> seen;\n        for (auto &ord : orders_raw) {\n            uint64_t h1 = hash_vec_ordered(ord);\n            if (!seen.count(h1)) {\n                seen.insert(h1);\n                orders.push_back(ord);\n            }\n            auto rev = reversed_copy(ord);\n            uint64_t h2 = hash_vec_ordered(rev);\n            if (!seen.count(h2)) {\n                seen.insert(h2);\n                orders.push_back(move(rev));\n            }\n        }\n\n        for (auto &ord : orders) {\n            for (auto &sz : size_seqs) cands.push_back(candidate_from_order(ord, sz));\n        }\n\n        for (auto &sz : size_seqs) {\n            for (int mode = 0; mode < 3; mode++) {\n                cands.push_back(candidate_from_kd(sz, mode));\n            }\n        }\n\n        Candidate best;\n        best.score = INF;\n        for (auto &c : cands) {\n            if (c.score < best.score) best = c;\n        }\n\n        auto groups = assign_to_original_indices(best.groups_seq);\n        local_swap_optimize(groups);\n        return groups;\n    }\n\n    vector<pair<int,int>> make_primary_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n < 2) return res;\n        int s = 0;\n        while (true) {\n            int len = min(L, n - s);\n            if (len < 2) break;\n            res.push_back({s, len});\n            if (s + len >= n) break;\n            s = s + len - 1;\n        }\n        return res;\n    }\n\n    vector<pair<int,int>> make_extra_windows_indices(int n) {\n        vector<pair<int,int>> res;\n        if (n <= L) return res;\n\n        auto primary = make_primary_windows_indices(n);\n        set<int> used_starts;\n        for (auto [s, len] : primary) used_starts.insert(s);\n\n        int max_start = n - L;\n        int shift = max(1, (L - 1) / 2);\n\n        for (int i = 0; i + 1 < (int)primary.size(); i++) {\n            int s1 = primary[i].first;\n            int s2 = primary[i + 1].first;\n            int cand = min(max_start, s1 + shift);\n            if (cand > s1 && cand < s2 && !used_starts.count(cand)) {\n                used_starts.insert(cand);\n                res.push_back({cand, L});\n            }\n            int cand2 = max(0, min(max_start, s2 - shift));\n            if (cand2 > s1 && cand2 < s2 && !used_starts.count(cand2)) {\n                used_starts.insert(cand2);\n                res.push_back({cand2, L});\n            }\n        }\n        return res;\n    }\n\n    double completed_tree_cost_from_keys(const vector<int>& group,\n                                         const unordered_set<uint64_t>& eset) {\n        int n = (int)group.size();\n        if (n <= 1) return 0.0;\n\n        vector<pair<double, pair<int,int>>> edges;\n        edges.reserve(eset.size());\n        for (auto key : eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(edges.begin(), edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        double cost = 0.0;\n        for (auto &e : edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) cost += e.first;\n        }\n\n        unordered_map<int, int> comp_id;\n        comp_id.reserve(n * 2);\n        int cc = 0;\n        for (int v : group) {\n            int r = dsu.find(v);\n            if (!comp_id.count(r)) comp_id[r] = cc++;\n        }\n        if (cc <= 1) return cost;\n\n        vector<vector<double>> best(cc, vector<double>(cc, INF));\n        for (int i = 0; i < n; i++) {\n            int u = group[i];\n            int cu = comp_id[dsu.find(u)];\n            for (int j = i + 1; j < n; j++) {\n                int v = group[j];\n                int cv = comp_id[dsu.find(v)];\n                if (cu == cv) continue;\n                double d = distm[u][v];\n                if (d < best[cu][cv]) {\n                    best[cu][cv] = best[cv][cu] = d;\n                }\n            }\n        }\n\n        vector<double> md(cc, INF);\n        vector<char> used(cc, 0);\n        md[0] = 0.0;\n        for (int it = 0; it < cc; it++) {\n            int v = -1;\n            for (int i = 0; i < cc; i++) {\n                if (!used[i] && (v == -1 || md[i] < md[v])) v = i;\n            }\n            used[v] = 1;\n            cost += md[v];\n            for (int to = 0; to < cc; to++) if (!used[to] && best[v][to] < md[to]) {\n                md[to] = best[v][to];\n            }\n        }\n        return cost;\n    }\n\n    double approx_union_tree_cost_for_order(const vector<int>& ord) {\n        int n = (int)ord.size();\n        if (n <= 1) return 0.0;\n        if (n <= L) return mst_cost_of_list(ord);\n\n        auto primary = make_primary_windows_indices(n);\n        unordered_set<uint64_t> eset;\n        eset.reserve(n * 8);\n\n        for (auto [s, len] : primary) {\n            vector<int> w(ord.begin() + s, ord.begin() + s + len);\n            auto e = approx_mst_edges_small(w);\n            for (auto [a, b] : e) eset.insert(edge_key(a, b));\n        }\n        return completed_tree_cost_from_keys(ord, eset);\n    }\n\n    vector<int> candidate_positions_for_local_search(int n, int seglen) {\n        vector<int> pos;\n        if (n <= 80) {\n            for (int i = 0; i + seglen <= n; i++) pos.push_back(i);\n            return pos;\n        }\n\n        set<int> st;\n        auto primary = make_primary_windows_indices(n);\n        for (auto [s, len] : primary) {\n            for (int d = -2; d <= 2; d++) {\n                int p1 = s + d;\n                if (0 <= p1 && p1 + seglen <= n) st.insert(p1);\n                int boundary = s + len - 1;\n                int p2 = boundary + d - seglen + 1;\n                if (0 <= p2 && p2 + seglen <= n) st.insert(p2);\n            }\n        }\n        int step = max(1, n / 24);\n        for (int i = 0; i + seglen <= n; i += step) st.insert(i);\n        if (n - seglen >= 0) st.insert(n - seglen);\n\n        pos.assign(st.begin(), st.end());\n        return pos;\n    }\n\n    vector<int> refine_local_order(vector<int> ord) {\n        int n = (int)ord.size();\n        if (n <= max(L, 3)) return ord;\n\n        double cur = approx_union_tree_cost_for_order(ord);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool improved = false;\n\n            // adjacent swaps\n            {\n                auto pos = candidate_positions_for_local_search(n, 2);\n                for (int i : pos) {\n                    swap(ord[i], ord[i + 1]);\n                    double sc = approx_union_tree_cost_for_order(ord);\n                    if (sc + 1e-9 < cur) {\n                        cur = sc;\n                        improved = true;\n                    } else {\n                        swap(ord[i], ord[i + 1]);\n                    }\n                }\n            }\n\n            // short reverses\n            for (int len : {3, 4, 5}) {\n                if (len > n) continue;\n                auto pos = candidate_positions_for_local_search(n, len);\n                for (int i : pos) {\n                    reverse(ord.begin() + i, ord.begin() + i + len);\n                    double sc = approx_union_tree_cost_for_order(ord);\n                    if (sc + 1e-9 < cur) {\n                        cur = sc;\n                        improved = true;\n                    } else {\n                        reverse(ord.begin() + i, ord.begin() + i + len);\n                    }\n                }\n            }\n\n            if (!improved) break;\n        }\n        return ord;\n    }\n\n    vector<int> choose_best_local_order(const vector<int>& group) {\n        int n = (int)group.size();\n        if (n <= 2) return group;\n\n        vector<vector<int>> raw;\n        raw.push_back(group);\n        raw.push_back(order_group_by_key(group, 5));\n        raw.push_back(order_group_by_key(group, 4));\n        raw.push_back(order_group_by_key(group, 0));\n        raw.push_back(order_group_by_key(group, 1));\n        raw.push_back(order_group_by_key(group, 2));\n        raw.push_back(order_group_by_key(group, 3));\n        raw.push_back(mst_preorder_order(group));\n        raw.push_back(nearest_neighbor_order(group, 0));\n        raw.push_back(nearest_neighbor_order(group, 1));\n\n        vector<vector<int>> cands;\n        unordered_set<uint64_t> seen;\n        seen.reserve(raw.size() * 4);\n\n        auto add_ord = [&](const vector<int>& ord) {\n            uint64_t h = hash_vec_ordered(ord);\n            if (!seen.count(h)) {\n                seen.insert(h);\n                cands.push_back(ord);\n            }\n        };\n\n        for (auto &ord : raw) {\n            add_ord(ord);\n            add_ord(reversed_copy(ord));\n        }\n\n        double best_score = INF;\n        vector<int> best = group;\n        for (auto &ord : cands) {\n            double sc = approx_union_tree_cost_for_order(ord);\n            if (sc < best_score) {\n                best_score = sc;\n                best = ord;\n            }\n        }\n\n        best = refine_local_order(best);\n        return best;\n    }\n\n    vector<pair<int,int>> query(const vector<int>& cities) {\n        cout << \"? \" << cities.size();\n        for (int v : cities) cout << \" \" << v;\n        cout << endl;\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)cities.size() - 1);\n        for (int i = 0; i < (int)cities.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            ret.push_back(norm_edge(a, b));\n        }\n        used_queries++;\n        return ret;\n    }\n\n    struct ExtraWindow {\n        int start, len;\n        vector<uint64_t> approx_edges;\n        double sub_cost;\n        bool used = false;\n    };\n\n    struct GroupPlan {\n        vector<int> order;\n        vector<pair<int,int>> primary;\n        vector<ExtraWindow> extras;\n        unordered_set<uint64_t> current_approx_edges;\n        double current_approx_cost = 0.0;\n        int version = 0;\n    };\n\n    struct PQNode {\n        double gain;\n        double sub_cost;\n        int gid;\n        int extra_idx;\n        int version;\n        bool operator<(const PQNode& other) const {\n            if (fabs(gain - other.gain) > 1e-9) return gain < other.gain;\n            if (fabs(sub_cost - other.sub_cost) > 1e-9) return sub_cost < other.sub_cost;\n            if (gid != other.gid) return gid > other.gid;\n            return extra_idx > other.extra_idx;\n        }\n    };\n\n    pair<double, bool> evaluate_extra_gain(const GroupPlan& plan, const ExtraWindow& ew) {\n        unordered_set<uint64_t> merged = plan.current_approx_edges;\n        merged.reserve(plan.current_approx_edges.size() + ew.approx_edges.size() * 2 + 8);\n        bool adds_new = false;\n        for (auto k : ew.approx_edges) {\n            if (!merged.count(k)) adds_new = true;\n            merged.insert(k);\n        }\n        if (!adds_new) return {0.0, false};\n        double new_cost = completed_tree_cost_from_keys(plan.order, merged);\n        return {plan.current_approx_cost - new_cost, true};\n    }\n\n    void push_best_extra_for_group(priority_queue<PQNode>& pq, vector<GroupPlan>& plans, int gid) {\n        double best_gain = 0.0;\n        double best_sub = 0.0;\n        int best_idx = -1;\n        for (int i = 0; i < (int)plans[gid].extras.size(); i++) {\n            if (plans[gid].extras[i].used) continue;\n            auto [gain, ok] = evaluate_extra_gain(plans[gid], plans[gid].extras[i]);\n            if (!ok) continue;\n            if (gain > best_gain + 1e-9 ||\n                (fabs(gain - best_gain) <= 1e-9 && plans[gid].extras[i].sub_cost > best_sub)) {\n                best_gain = gain;\n                best_sub = plans[gid].extras[i].sub_cost;\n                best_idx = i;\n            }\n        }\n        if (best_idx != -1 && best_gain > 1e-9) {\n            pq.push({best_gain, best_sub, gid, best_idx, plans[gid].version});\n        }\n    }\n\n    vector<pair<int,int>> final_tree_from_edge_union(\n        const vector<int>& group,\n        const unordered_set<uint64_t>& exact_eset\n    ) {\n        int n = (int)group.size();\n        if (n <= 1) return {};\n\n        vector<pair<double, pair<int,int>>> exact_edges;\n        exact_edges.reserve(exact_eset.size());\n        for (auto key : exact_eset) {\n            int a = int(key >> 32);\n            int b = int(key & 0xffffffffu);\n            exact_edges.push_back({distm[a][b], {a, b}});\n        }\n        sort(exact_edges.begin(), exact_edges.end(), [&](auto &x, auto &y) {\n            if (fabs(x.first - y.first) > 1e-9) return x.first < y.first;\n            return x.second < y.second;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> ans;\n        ans.reserve(n - 1);\n\n        for (auto &e : exact_edges) {\n            int a = e.second.first, b = e.second.second;\n            if (dsu.unite(a, b)) ans.push_back({a, b});\n        }\n\n        unordered_map<int, int> comp_id;\n        comp_id.reserve(n * 2);\n        vector<int> roots;\n        for (int v : group) {\n            int r = dsu.find(v);\n            if (!comp_id.count(r)) {\n                int id = (int)roots.size();\n                comp_id[r] = id;\n                roots.push_back(r);\n            }\n        }\n        int cc = (int)roots.size();\n        if (cc <= 1) return ans;\n\n        struct CEdge {\n            double d;\n            int a, b;\n            int cu, cv;\n        };\n        vector<CEdge> cand;\n        cand.reserve((size_t)n * (n - 1) / 2);\n\n        for (int i = 0; i < n; i++) {\n            int u = group[i];\n            int cu = comp_id[dsu.find(u)];\n            for (int j = i + 1; j < n; j++) {\n                int v = group[j];\n                int cv = comp_id[dsu.find(v)];\n                if (cu == cv) continue;\n                cand.push_back({distm[u][v], u, v, cu, cv});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const CEdge& x, const CEdge& y) {\n            if (fabs(x.d - y.d) > 1e-9) return x.d < y.d;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        DSU comp_dsu(cc);\n        for (auto &e : cand) {\n            if (comp_dsu.unite(e.cu, e.cv)) {\n                ans.push_back(norm_edge(e.a, e.b));\n                if ((int)ans.size() == n - 1) break;\n            }\n        }\n\n        if ((int)ans.size() != n - 1) return approx_mst_edges_full(group);\n        return ans;\n    }\n\n    void solve() {\n        input();\n\n        auto groups = build_groups();\n\n        vector<GroupPlan> plans(M);\n        int primary_queries = 0;\n\n        for (int gid = 0; gid < M; gid++) {\n            plans[gid].order = choose_best_local_order(groups[gid]);\n            int n = (int)plans[gid].order.size();\n            plans[gid].primary = make_primary_windows_indices(n);\n            auto extra_idx = make_extra_windows_indices(n);\n            primary_queries += (int)plans[gid].primary.size();\n\n            plans[gid].current_approx_edges.reserve(max(8, n * 4));\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(plans[gid].order.begin() + s, plans[gid].order.begin() + s + len);\n                auto es = approx_mst_edges_small(w);\n                for (auto [a, b] : es) plans[gid].current_approx_edges.insert(edge_key(a, b));\n            }\n            plans[gid].current_approx_cost =\n                completed_tree_cost_from_keys(plans[gid].order, plans[gid].current_approx_edges);\n\n            for (auto [s, len] : extra_idx) {\n                vector<int> w(plans[gid].order.begin() + s, plans[gid].order.begin() + s + len);\n                auto es = approx_mst_edges_small(w);\n                vector<uint64_t> keys;\n                keys.reserve(es.size());\n                for (auto [a, b] : es) keys.push_back(edge_key(a, b));\n                double subc = mst_cost_of_list(w);\n                plans[gid].extras.push_back({s, len, move(keys), subc, false});\n            }\n        }\n\n        int remain = max(0, Q - primary_queries);\n\n        priority_queue<PQNode> pq;\n        for (int gid = 0; gid < M; gid++) push_best_extra_for_group(pq, plans, gid);\n\n        vector<vector<pair<int,int>>> chosen_extras(M);\n\n        while (remain > 0 && !pq.empty()) {\n            auto cur = pq.top();\n            pq.pop();\n            if (cur.version != plans[cur.gid].version) continue;\n            if (plans[cur.gid].extras[cur.extra_idx].used) continue;\n\n            auto [gain, ok] = evaluate_extra_gain(plans[cur.gid], plans[cur.gid].extras[cur.extra_idx]);\n            if (!ok || gain + 1e-9 < cur.gain) {\n                push_best_extra_for_group(pq, plans, cur.gid);\n                continue;\n            }\n            if (gain <= 1e-9) break;\n\n            auto &ew = plans[cur.gid].extras[cur.extra_idx];\n            ew.used = true;\n            chosen_extras[cur.gid].push_back({ew.start, ew.len});\n            for (auto k : ew.approx_edges) plans[cur.gid].current_approx_edges.insert(k);\n            plans[cur.gid].current_approx_cost =\n                completed_tree_cost_from_keys(plans[cur.gid].order, plans[cur.gid].current_approx_edges);\n            plans[cur.gid].version++;\n            push_best_extra_for_group(pq, plans, cur.gid);\n            remain--;\n        }\n\n        vector<unordered_set<uint64_t>> edge_unions(M);\n        for (int i = 0; i < M; i++) edge_unions[i].reserve(max(8, (int)groups[i].size() * 4));\n\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : plans[gid].primary) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (auto [s, len] : chosen_extras[gid]) {\n                vector<int> w(ord.begin() + s, ord.begin() + s + len);\n                auto ret = query(w);\n                for (auto [a, b] : ret) edge_unions[gid].insert(edge_key(a, b));\n            }\n        }\n\n        vector<vector<pair<int,int>>> answer_edges(M);\n        for (int gid = 0; gid < M; gid++) {\n            answer_edges[gid] = final_tree_from_edge_union(plans[gid].order, edge_unions[gid]);\n        }\n\n        cout << \"!\" << endl;\n        for (int gid = 0; gid < M; gid++) {\n            auto &ord = plans[gid].order;\n            for (int i = 0; i < (int)ord.size(); i++) {\n                if (i) cout << ' ';\n                cout << ord[i];\n            }\n            cout << '\\n';\n            for (auto [a, b] : answer_edges[gid]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int POS = N * N;          // 400\nstatic constexpr int NONE = POS;           // 400\nstatic constexpr int BNUM = POS + 1;       // 401\nstatic constexpr int STATES = POS * BNUM;  // 160400\n\nstatic constexpr int INF = 30000;\nstatic constexpr int MAXDIST = 2000; // enough for 40 targets on 20x20\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar dch[4] = {'U', 'D', 'L', 'R'};\n\ninline int sid1(int pos, int b) { return pos * BNUM + b; }\ninline int pos_of_1(int s) { return s / BNUM; }\ninline int block_of_1(int s) { return s % BNUM; }\ninline bool valid_state_1(int pos, int b) { return b == NONE || b != pos; }\n\nint neigh[POS][4];\nunsigned short slide_to_1[BNUM][POS][4];\nstatic vector<unsigned short> revSlide[BNUM][POS];\n\nvector<unsigned short> dist_all;\nstatic vector<int> buckets[MAXDIST + 1];\n\nstruct Action {\n    char a, d;\n};\n\ninline unsigned short* stage_ptr(int k) {\n    return dist_all.data() + (size_t)k * STATES;\n}\n\n// ---------- 2-block temporary model ----------\ninline void canon2(int &b1, int &b2) {\n    if (b1 == NONE) {\n        b2 = NONE;\n        return;\n    }\n    if (b2 == NONE) return;\n    if (b2 < b1) swap(b1, b2);\n}\n\ninline bool valid_state_2(int pos, int b1, int b2) {\n    if (b1 != NONE && b1 == pos) return false;\n    if (b2 != NONE && b2 == pos) return false;\n    return true;\n}\n\ninline int encode2(int pos, int b1, int b2) {\n    // phase-less code\n    return ((b1 * BNUM + b2) * POS + pos);\n}\n\ninline void decode2(int code, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    b1 = t / BNUM;\n}\n\ninline int encodeP(int phase, int pos, int b1, int b2) {\n    return ((((phase * BNUM) + b1) * BNUM + b2) * POS + pos);\n}\n\ninline void decodeP(int code, int &phase, int &pos, int &b1, int &b2) {\n    pos = code % POS;\n    int t = code / POS;\n    b2 = t % BNUM;\n    t /= BNUM;\n    b1 = t % BNUM;\n    phase = t / BNUM;\n}\n\ninline int slide_to_2(int pos, int b1, int b2, int dir) {\n    int cur = pos;\n    while (true) {\n        int np = neigh[cur][dir];\n        if (np == -1) break;\n        if (np == b1 || np == b2) break;\n        cur = np;\n    }\n    return cur;\n}\n\nvoid precompute() {\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int p = r * N + c;\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                    neigh[p][d] = nr * N + nc;\n                } else {\n                    neigh[p][d] = -1;\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int p = 0; p < POS; p++) {\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; d++) {\n                int cr = r, cc = c;\n                while (true) {\n                    int nr = cr + dr[d], nc = cc + dc[d];\n                    if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) break;\n                    int np = nr * N + nc;\n                    if (b != NONE && np == b) break;\n                    cr = nr;\n                    cc = nc;\n                }\n                slide_to_1[b][p][d] = (unsigned short)(cr * N + cc);\n            }\n        }\n    }\n\n    for (int b = 0; b < BNUM; b++) {\n        for (int q = 0; q < POS; q++) {\n            if (!valid_state_1(q, b)) continue;\n            for (int d = 0; d < 4; d++) {\n                int p = slide_to_1[b][q][d];\n                if (p != q && valid_state_1(p, b)) {\n                    revSlide[b][p].push_back((unsigned short)q);\n                }\n            }\n        }\n    }\n}\n\nvoid compute_stage_dist(int k, const vector<int>& pts, int M) {\n    unsigned short* dist = stage_ptr(k);\n    for (int i = 0; i < STATES; i++) dist[i] = INF;\n    for (int i = 0; i <= MAXDIST; i++) buckets[i].clear();\n\n    int target_next = pts[k + 1];\n    unsigned short* next_dist = (k + 1 < M - 1 ? stage_ptr(k + 1) : nullptr);\n\n    int max_used = 0;\n\n    for (int b = 0; b < BNUM; b++) {\n        if (!valid_state_1(target_next, b)) continue;\n        int s = sid1(target_next, b);\n        unsigned short init_cost = (k + 1 == M - 1 ? 0 : next_dist[s]);\n        dist[s] = init_cost;\n        if (init_cost <= MAXDIST) {\n            buckets[init_cost].push_back(s);\n            max_used = max(max_used, (int)init_cost);\n        }\n    }\n\n    auto relax = [&](int ns, int nd) {\n        if (nd > MAXDIST) return;\n        if (nd < dist[ns]) {\n            dist[ns] = (unsigned short)nd;\n            buckets[nd].push_back(ns);\n            if (nd > max_used) max_used = nd;\n        }\n    };\n\n    for (int cd = 0; cd <= max_used; cd++) {\n        auto &bk = buckets[cd];\n        for (size_t it = 0; it < bk.size(); it++) {\n            int s = bk[it];\n            if (dist[s] != cd) continue;\n\n            int p = pos_of_1(s);\n            int b = block_of_1(s);\n            int nd = cd + 1;\n\n            // reverse of Move\n            for (int d = 0; d < 4; d++) {\n                int q = neigh[p][d];\n                if (q == -1) continue;\n                if (!valid_state_1(q, b)) continue;\n                relax(sid1(q, b), nd);\n            }\n\n            // reverse of Slide\n            for (unsigned short q : revSlide[b][p]) {\n                relax(sid1((int)q, b), nd);\n            }\n\n            // reverse of Alter\n            if (b == NONE) {\n                for (int d = 0; d < 4; d++) {\n                    int a = neigh[p][d];\n                    if (a == -1) continue;\n                    relax(sid1(p, a), nd);\n                }\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    if (neigh[p][d] == b) {\n                        relax(sid1(p, NONE), nd);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid reconstruct_baseline_segment(\n    int k,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    vector<Action>& seg,\n    int& end_block\n) {\n    seg.clear();\n    int target = pts[k + 1];\n    unsigned short* dist = stage_ptr(k);\n\n    int p = start_pos;\n    int b = start_block;\n    int curd = dist[sid1(p, b)];\n\n    while (p != target) {\n        bool found = false;\n\n        auto take = [&](char ac, int dir, int np, int nb) -> bool {\n            if (!valid_state_1(np, nb)) return false;\n            if (dist[sid1(np, nb)] + 1 != curd) return false;\n            seg.push_back({ac, dch[dir]});\n            p = np;\n            b = nb;\n            curd = dist[sid1(p, b)];\n            return true;\n        };\n\n        // prefer slide, then move, then alter\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int sp = slide_to_1[b][p][dir];\n            if (sp != p) found = take('S', dir, sp, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int np = neigh[p][dir];\n            if (np != -1 && np != b) found = take('M', dir, np, b);\n        }\n        for (int dir = 0; dir < 4 && !found; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n            if (b == NONE) found = take('A', dir, p, ap);\n            else if (b == ap) found = take('A', dir, p, NONE);\n        }\n\n        if (!found) break; // should not happen\n    }\n\n    end_block = b;\n}\n\nstruct TempNode {\n    int code;         // encoded (phase, pos, b1, b2)\n    int parent;\n    unsigned char op; // 0..11\n    unsigned short dist;\n};\n\n// horizon = 1 or 2\nbool try_improve_horizon(\n    int stage,\n    int horizon,\n    int start_pos,\n    int start_block,\n    const vector<int>& pts,\n    int M,\n    int baseline_total,\n    const vector<int>& best_from_checkpoint,\n    vector<Action>& improved_seg,\n    int& improved_end_block\n) {\n    improved_seg.clear();\n    improved_end_block = start_block;\n\n    int end_idx = stage + horizon;\n    int min_future = best_from_checkpoint[end_idx];\n    int gmax = baseline_total - min_future - 1;\n    if (gmax <= 0) return false;\n\n    // Practical cap: enough to capture most useful local improvements\n    gmax = min(gmax, 40);\n\n    vector<TempNode> nodes;\n    nodes.reserve(50000);\n    vector<int> q;\n    q.reserve(50000);\n\n    unordered_map<int, int> id;\n    id.reserve(70000);\n    id.max_load_factor(0.7f);\n\n    auto push_state = [&](int code, int parent, unsigned char op, int nd) {\n        auto it = id.find(code);\n        if (it != id.end()) return;\n        int idx = (int)nodes.size();\n        id.emplace(code, idx);\n        nodes.push_back({code, parent, op, (unsigned short)nd});\n        q.push_back(idx);\n    };\n\n    int b1 = (start_block == NONE ? NONE : start_block);\n    int b2 = NONE;\n    int start_code = encodeP(0, start_pos, b1, b2);\n    push_state(start_code, -1, 255, 0);\n\n    int best_idx = -1;\n    int best_total = baseline_total;\n\n    for (size_t qi = 0; qi < q.size(); qi++) {\n        int idx = q[qi];\n        const auto &nd = nodes[idx];\n\n        int phase, p, x1, x2;\n        decodeP(nd.code, phase, p, x1, x2);\n\n        if (phase == horizon && x2 == NONE) {\n            int endb = x1;\n            int future = (end_idx == M - 1 ? 0 : stage_ptr(end_idx)[sid1(pts[end_idx], endb)]);\n            int total = nd.dist + future;\n            if (total < best_total) {\n                best_total = total;\n                best_idx = idx;\n            }\n        }\n\n        if (nd.dist >= gmax) continue;\n        if ((int)nodes.size() > 180000) break; // emergency cap\n\n        int nextd = nd.dist + 1;\n\n        auto advance_phase = [&](int cur_phase, char act, int np) -> int {\n            if (act == 'A') return cur_phase;\n            if (cur_phase < horizon && np == pts[stage + cur_phase + 1]) return cur_phase + 1;\n            return cur_phase;\n        };\n\n        // Move\n        for (int dir = 0; dir < 4; dir++) {\n            int np = neigh[p][dir];\n            if (np == -1) continue;\n            if (np == x1 || np == x2) continue;\n            int nphase = advance_phase(phase, 'M', np);\n            push_state(encodeP(nphase, np, x1, x2), idx, (unsigned char)(0 + dir), nextd);\n        }\n\n        // Slide\n        for (int dir = 0; dir < 4; dir++) {\n            int sp = slide_to_2(p, x1, x2, dir);\n            if (sp == p) continue;\n            int nphase = advance_phase(phase, 'S', sp);\n            push_state(encodeP(nphase, sp, x1, x2), idx, (unsigned char)(4 + dir), nextd);\n        }\n\n        // Alter\n        for (int dir = 0; dir < 4; dir++) {\n            int ap = neigh[p][dir];\n            if (ap == -1) continue;\n\n            int nb1 = x1, nb2 = x2;\n\n            if (ap == x1) {\n                if (x2 == NONE) {\n                    nb1 = NONE;\n                    nb2 = NONE;\n                } else {\n                    nb1 = x2;\n                    nb2 = NONE;\n                }\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else if (ap == x2) {\n                nb2 = NONE;\n                push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n            } else {\n                if (x2 == NONE) {\n                    if (x1 == NONE) {\n                        nb1 = ap;\n                        nb2 = NONE;\n                    } else {\n                        nb1 = x1;\n                        nb2 = ap;\n                        canon2(nb1, nb2);\n                    }\n                    if (valid_state_2(p, nb1, nb2)) {\n                        push_state(encodeP(phase, p, nb1, nb2), idx, (unsigned char)(8 + dir), nextd);\n                    }\n                }\n            }\n        }\n    }\n\n    if (best_idx == -1) return false;\n\n    vector<unsigned char> ops;\n    int cur = best_idx;\n    while (nodes[cur].parent != -1) {\n        ops.push_back(nodes[cur].op);\n        cur = nodes[cur].parent;\n    }\n    reverse(ops.begin(), ops.end());\n\n    for (unsigned char op : ops) {\n        char a = (op < 4 ? 'M' : op < 8 ? 'S' : 'A');\n        char d = dch[op & 3];\n        improved_seg.push_back({a, d});\n    }\n\n    int phase, p, y1, y2;\n    decodeP(nodes[best_idx].code, phase, p, y1, y2);\n    improved_end_block = y1;\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    int Nin, M;\n    cin >> Nin >> M;\n    vector<int> pts(M);\n    for (int i = 0; i < M; i++) {\n        int r, c;\n        cin >> r >> c;\n        pts[i] = r * N + c;\n    }\n\n    if (M == 1) return 0;\n\n    dist_all.assign((size_t)(M - 1) * STATES, (unsigned short)INF);\n\n    for (int k = M - 2; k >= 0; k--) {\n        compute_stage_dist(k, pts, M);\n    }\n\n    // best_from_checkpoint[idx]:\n    // minimal remaining cost from position pts[idx] with 0/1 block state\n    // after target idx has just been visited.\n    vector<int> best_from_checkpoint(M, 0);\n    best_from_checkpoint[M - 1] = 0;\n    for (int idx = 1; idx <= M - 2; idx++) {\n        int best = INF;\n        unsigned short* dist = stage_ptr(idx);\n        for (int b = 0; b < BNUM; b++) {\n            if (!valid_state_1(pts[idx], b)) continue;\n            best = min(best, (int)dist[sid1(pts[idx], b)]);\n        }\n        best_from_checkpoint[idx] = best;\n    }\n\n    vector<Action> ans;\n    ans.reserve(1600);\n\n    int cur_pos = pts[0];\n    int cur_block = NONE;\n    int stage = 0;\n\n    while (stage < M - 1) {\n        int baseline_total = stage_ptr(stage)[sid1(cur_pos, cur_block)];\n\n        bool improved = false;\n        vector<Action> seg;\n        int end_block = NONE;\n\n        // First try 2-stage local search (spanning one target boundary)\n        if (stage + 2 <= M - 1) {\n            improved = try_improve_horizon(\n                stage, 2, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 2];\n                cur_block = end_block;\n                stage += 2;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // For the final single stage, try 1-stage temporary 2-block improvement\n        if (stage + 1 == M - 1) {\n            improved = try_improve_horizon(\n                stage, 1, cur_pos, cur_block, pts, M,\n                baseline_total, best_from_checkpoint, seg, end_block\n            );\n            if (improved) {\n                for (auto &x : seg) ans.push_back(x);\n                cur_pos = pts[stage + 1];\n                cur_block = end_block;\n                stage += 1;\n                if ((int)ans.size() > 2 * N * M) break;\n                continue;\n            }\n        }\n\n        // Fallback: exact 1-block baseline, one stage\n        vector<Action> base_seg;\n        int base_end_block = NONE;\n        reconstruct_baseline_segment(stage, cur_pos, cur_block, pts, base_seg, base_end_block);\n        for (auto &x : base_seg) ans.push_back(x);\n        cur_pos = pts[stage + 1];\n        cur_block = base_end_block;\n        stage += 1;\n\n        if ((int)ans.size() > 2 * N * M) break;\n    }\n\n    if ((int)ans.size() > 2 * N * M) {\n        ans.resize(2 * N * M);\n    }\n\n    for (auto &x : ans) {\n        cout << x.a << ' ' << x.d << '\\n';\n    }\n    return 0;\n}"}}}